//+------------------------------------------------------------------+
//|                                            QTFx TMA bands EA.mq4 |
//|                                                         satheesh |
//|                                           http://qualitechfx.com |
//+------------------------------------------------------------------+
#property copyright "satheesh"
#property link      "http://qualitechfx.com"
#property version   "1.00"
#property strict
extern string TimeFrame       = "current time frame";
extern bool BUY_ONLY  = true; 
extern bool SELL_ONLY = true;
extern double Lots      = 0.05;

extern bool   UseLotsPerRiskCalculation=FALSE;
extern double RiskPercentage=2.0;
extern int    Magic = 12345;

extern string rah2="SET STOPLOSS & TAKE PROFIT";
extern double StopLoss     = 100.0;
extern double TakeProfit   = 200.0;
extern int Slippage     = 3;
int slippagepips;
double pips2dbl;
int openorders;
int MinBarsBetweenTradesOfSameType = 1;
extern int    HalfLength      = 56;
extern int    Price           = PRICE_WEIGHTED;
extern double BandsDeviations = 2.5;
bool   DoFreeMarginCheck          = FALSE;
bool   DoFreeMarginForSlAlsoCheck = FALSE;
extern bool   showPrice       = true;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   BrokerDigitAdjust(Symbol());
   slippagepips = Slippage;
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert Start function                                            |
//+------------------------------------------------------------------+
int start()
  {
  int i,j;
   int totalOrders;
   int result;
   bool openorder;
  
   double Midlevel = iCustom(Symbol(),0,"TMA bands qtfx",TimeFrame,HalfLength,Price,BandsDeviations,showPrice,0,1);
   double Uplevel = iCustom(Symbol(),0,"TMA bands qtfx",TimeFrame,HalfLength,Price,BandsDeviations,showPrice,1,1);
   double Downlevel = iCustom(Symbol(),0,"TMA bands qtfx",TimeFrame,HalfLength,Price,BandsDeviations,showPrice,2,1);
   int currentprice = MarketInfo(Symbol(),MODE_BID);
    totalOrders=OrdersTotal();
      for (i=0;i<totalOrders;i++)
      {
         if (OrderSelect(i, SELECT_BY_POS) == false) continue;
         if ((OrderSymbol() == Symbol()) && (OrderMagicNumber() == Magic))
         {
            
            if (OrderType() == OP_BUY && currentprice == Midlevel)
            {
               Print("closing long position");
               RefreshRates();
            while (IsTradeContextBusy()) Sleep(100);
             result=OrderClose(OrderTicket(), OrderLots(), Bid, 99999, CLR_NONE);
            }
            
            if (OrderType() == OP_SELL && currentprice == Midlevel)
            {
               RefreshRates();
            while (IsTradeContextBusy()) Sleep(100);
            result=OrderClose(OrderTicket(), OrderLots(), Ask, 99999, CLR_NONE);
            }
         } // end if symbol
      } // end for i
     
  
   totalOrders=OrdersTotal();
      for (j=0;j<totalOrders;j++)
      {
         if (OrderSelect(j, SELECT_BY_POS) == false) continue;
         if ((OrderSymbol() == Symbol()) && (OrderMagicNumber() == Magic))
         {
            // If the stop has flopped to the other side of the trade then close it.
            if (OrderType() == OP_BUY ||OP_SELL)
            {
               openorder = true;
            }
            }
            
   
     }
   if (currentprice >= Uplevel && ! openorder )
   {
       
        
                   Print ("Creating buy orders");
                  fSell();
                 
           
                  Print("BUY orders opened : ",OrderOpenPrice());
                  
               }
  
 if (currentprice <= Downlevel && ! openorder)
 {
      
         
            Print ("Creating sell orders");
            fBuy();
           
            
            
                 Print("SELL orders opened : ",OrderOpenPrice());
                 
               }
               return(0);
   
  }

//+------------------------------------------------------------------+
//| Sell                                                             |
//+------------------------------------------------------------------+
int fSell()
{
    
   
   
  
	double SL = 0, TP = 0;
	RefreshRates();
   double bid = MarketInfo(Symbol(),MODE_BID);
   double ask = MarketInfo(Symbol(),MODE_ASK);
   if (StopLoss   > 0.0000) SL = ask + (StopLoss * pips2dbl);
   if (TakeProfit > 0.0000) TP = ask - (TakeProfit * pips2dbl);
    //Print("**** SELL at "+DoubleToStr(bid,Digits)+", SL("+DoubleToStr(StopLoss,2)+")="+DoubleToStr(SL,Digits)+", TP("+DoubleToStr(TakeProfit,2)+"="+DoubleToStr(TP,Digits));
   int result = OrderSend2Stage(Symbol(), OP_SELL, Lots, bid, Slippage, SL, TP, "QTFx SCALPER: "+Symbol()+" SELL", Magic,0,CLR_NONE);
	return(0);
}


//+------------------------------------------------------------------+
//| Buy                                                              |
//+------------------------------------------------------------------+
int fBuy()
{
   
   
	double SL = 0, TP = 0;
	RefreshRates();
   double bid = MarketInfo(Symbol(),MODE_BID);
   double ask = MarketInfo(Symbol(),MODE_ASK);
   if (StopLoss   > 0.0000) SL = bid - (StopLoss * pips2dbl);
   if (TakeProfit > 0.0000) TP = bid + (TakeProfit * pips2dbl);
    //Print("**** BUY at "+DoubleToStr(ask,Digits)+", SL("+DoubleToStr(StopLoss,2)+")="+DoubleToStr(SL,Digits)+", TP("+DoubleToStr(TakeProfit,2)+"="+DoubleToStr(TP,Digits));
	int result = OrderSend2Stage(Symbol(), OP_BUY, Lots, ask, Slippage, SL, TP, "QTFx SCALPER: "+Symbol()+" BUY", Magic,0,CLR_NONE);
   return(0);
}


//+------------------------------------------------------------------+

void BrokerDigitAdjust(string symbol) {
 int Multiplier = 1;
 int digits=MarketInfo(symbol,MODE_DIGITS);
 if (digits==3 || digits==5) Multiplier = 10;
 if (digits==6) Multiplier = 100;   
 if (digits==7) Multiplier = 1000;
 pips2dbl = Multiplier*MarketInfo(symbol,MODE_POINT);
 Slippage=slippagepips*Multiplier;
}
bool OrderSend2Stage(string symbol,int type,double lots,double price,int slippage,double sl,double tp,string ocomment,int magic,datetime expiry,color col) {
// TradeTimeOk = CheckTradingTimes();
 //if (!TradeTimeOk) return(0);
 if (!BUY_ONLY  && type==OP_BUY) return(0);
 if (!SELL_ONLY && type==OP_SELL) return(0);
 bool result=true;
 int ticket;RefreshRates();
 //lots = NormalizeLots(symbol,lots);
 lots = CalcLotsAndCheckMargin(symbol,type,lots,RiskPercentage,price,sl);
  if (!OCTimeLastOrderSameTypeOk(symbol,type,magic)) return(0);
  while (IsTradeContextBusy()) Sleep(100);
  ticket=OrderSend(symbol,type,lots,price,slippage,0,0,ocomment,magic,expiry,col);
  while (IsTradeContextBusy()) Sleep(100);
   if (!OrderSelect(ticket, SELECT_BY_TICKET)) {
    //Print(" *** ERROR -> COULD NOT SELECT ORDERTICKET "+OrderTicket()+" *** ");
    return(false);
   }
   //Print("**** send ORDER at "+DoubleToStr(price,Digits)+", SL("+DoubleToStr(StopLoss,2)+")="+DoubleToStr(sl,Digits)+", TP("+DoubleToStr(TakeProfit,2)+"="+DoubleToStr(tp,Digits));
    if (sl!=0.00000 && tp!=0.00000) result = OrderModify(OrderTicket(),OrderOpenPrice(),NormalizePrice(OrderSymbol(),sl),NormalizePrice(OrderSymbol(),tp),OrderExpiration(),CLR_NONE);
    if (sl!=0.00000 && tp==0.00000) result = OrderModify(OrderTicket(),OrderOpenPrice(),NormalizePrice(OrderSymbol(),sl),OrderTakeProfit(),OrderExpiration(),CLR_NONE);
    if (sl==0.00000 && tp!=0.00000) result = OrderModify(OrderTicket(),OrderOpenPrice(),OrderStopLoss(),NormalizePrice(OrderSymbol(),tp),OrderExpiration(),CLR_NONE);
  
 return(result);
}

bool OCTimeLastOrderSameTypeOk(string symbol,int type,int magicnumber) {
int cnt;
 if (MinBarsBetweenTradesOfSameType==0) return(true);
 //History
 for ( cnt=OrdersHistoryTotal()-1; cnt>=0; cnt--) {
  if (!OrderSelect(cnt,SELECT_BY_POS,MODE_HISTORY)) continue;
  if (OrderSymbol()!=symbol) continue;
  if (OrderMagicNumber()!=magicnumber) continue;
  if (OrderType()!=type) continue;
   {//start loop
     if (TimeCurrent() - OrderCloseTime() < (MinBarsBetweenTradesOfSameType * Period() * 60)) return(false);
   }//end loop
 }//for (int cnt=OrdersHistoryTotal()-1; cnt>=0; cnt--) {
 
 //Open Trades:
 for (cnt=OrdersTotal()-1; cnt>=0; cnt--) {
  if (!OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES)) continue;
  if (OrderSymbol()!=symbol) continue;
  if (OrderMagicNumber()!=magicnumber) continue;
  if (OrderType()!=type) continue;
   {//start loop
     if (OrderOpenTime()>=iTime(OrderSymbol(),0,0)) return(false);
     if (TimeCurrent() - OrderOpenTime() < (MinBarsBetweenTradesOfSameType * Period() * 60)) return(false);
   }//end loop
 }//for (int cnt=OrdersTotal()-1; cnt>=0; cnt--) {
return(true);
}

//Lot size must be adjusted to be a multiple of lotstep, which may not be a power of ten on some brokers
double NormalizeLots(string symbol, double lots) {
  if (MathAbs(lots)<MarketInfo(symbol,MODE_MINLOT)) return(MarketInfo(symbol,MODE_MINLOT));
  if (MathAbs(lots)>MarketInfo(symbol,MODE_MAXLOT)) return(MarketInfo(symbol,MODE_MAXLOT));
  double ls = MarketInfo(symbol,MODE_LOTSTEP); 
  lots=MathRound(lots/ls)*ls;
  return(MathMin(MarketInfo(symbol,MODE_MAXLOT),MathMax(MarketInfo(symbol,MODE_MINLOT),lots))); 
}//double NormalizeLots(string symbol, double lots) {


//Open price for pending order must be adjusted to be a multiple of ticksize, not point, and on metals they are not the same.
//see also http://forum.mql4.com/45425#564188
double NormalizePrice(string symbol, double price) {
 if (price==0.00000000) return(0.0);
 double ts = MarketInfo(symbol,MODE_TICKSIZE);
return(MathRound(price/ts)*ts );
}





/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//risk/lots calculation stuff:
double CalcLotsAndCheckMargin(string symbol,int type,double lots,double RiskPercentage,double price,double SLprice) {
  
 if (MathAbs(RiskPercentage)>0.000 && UseLotsPerRiskCalculation) lots = CalculateLotSize(symbol,RiskPercentage,lots,price,SLprice);//if using risk-based calculation
 if (DoFreeMarginCheck) lots = FreeMarginCheck(symbol,type,lots,price,SLprice);//do we have enough free margin?
  else if (!DoFreeMarginCheck) lots = NormalizeLots(symbol,lots);
 return(lots);
}

double CalculateLotSize(string symbol,double RiskPercent,double lots,double BidAskPrice,double SLprice) {
   
      
  
  //mod. - if there is no SLprice specified, the script would work with 50 pips (you can change that, search for the 30 in the code some lines below) ...
  if (SLprice==0) SLprice = BidAskPrice+(50*pips2dbl);
    
   lots = NormalizeLots(symbol,lots);
   if (RiskPercent==0.0) return(lots); 
   if (BidAskPrice == 0.00000 || SLprice == 0.00000) return(lots);
   
   double FreeMargin = AccountFreeMargin();
    //double TickValue = MarketInfo(symbol,MODE_TICKVALUE) ;   
   double TickValue = MarketInfo(symbol,MODE_TICKVALUE) * MarketInfo(symbol,MODE_POINT) / MarketInfo(symbol,MODE_TICKSIZE);

   double LotStep = MarketInfo(symbol,MODE_LOTSTEP);
   double SLPts = MathAbs(BidAskPrice - SLprice);
   
   SLPts/= MarketInfo(symbol,MODE_POINT);//No idea why *= factor does not work here, but it doesn't
   
   double Exposure = SLPts * TickValue; // Exposure based on 1 full lot

   double AllowedExposure = (FreeMargin * RiskPercent) / 100;
   
   //int TotalSteps = ((AllowedExposure / Exposure) / LotStep);
   double TotalSteps = ((AllowedExposure / Exposure) / LotStep); 
   double LotSize = TotalSteps * LotStep;
   
   return(NormalizeLots(symbol,LotSize));
}//double CalculateLotSize(string symbol,double RiskPercent,double lots,double BidAskPrice,double SLprice) {

///////////////////////////////////////////////////////////////////////////////
//start freemargincheck
/*
  Usage: before the OrderSend-Command you may set your already calculated lotsize = FreeMarginCheck(string symbol,int ordertype,double lots,double BidAskPrice,double SLprice)
  if there is no SLprice specified, the script would work with 50 pips (you can change that, search for the 30 in the code some lines below) ...
*/

double FreeMarginCheck(string symbol,int ordertype,double lots,double BidAskPrice,double SLprice) { 
  lots = NormalizeLots(symbol,lots);
  if (CheckAccountFreeMargin(symbol,ordertype,lots)) return(lots);//everything ok
 
  //adjust:
  Print("... not enough money, will try to decrease lotsize of "+DoubleToStr(lots,MarketInfo(symbol,MODE_DIGITS))+" (max. lots: "+DoubleToStr(MarketInfo(symbol,MODE_MAXLOT),MarketInfo(symbol,MODE_DIGITS))+" | min. lots: "+DoubleToStr(MarketInfo(symbol,MODE_MINLOT),MarketInfo(symbol,MODE_DIGITS))+") ...");
  if (SLprice==0.0) {
    //x-digit broker adjust
     int Multiplier = 1;
     double digits=MarketInfo(symbol,MODE_DIGITS);
     if (digits==3 || digits==5) Multiplier = 10;
     if (digits==6) Multiplier = 100;   
     if (digits==7) Multiplier = 1000;
     pips2dbl = Multiplier*MarketInfo(symbol,MODE_POINT); 
    //end x-digit broker adjust
   Print("... no SL specified, will count with 30 pips instead ...");
   SLprice = BidAskPrice+(30*pips2dbl);
  }//if (SLprice==0.0) {
  
  double ls=MarketInfo(symbol,MODE_LOTSTEP);
  while (!CheckAccountFreeMargin(symbol,ordertype,lots))
   {
    //lots = lots - ls;
    lots = NormalizeLots(symbol,lots - ls);
   }//while (!CheckAccountFreeMargin(symbol,ordertype,lots))
  
  if (DoFreeMarginForSlAlsoCheck) {
   Print("... lotsize adjusted to "+DoubleToStr(lots,MarketInfo(symbol,MODE_DIGITS))+", checking for enough free margin for SL now ...");
   lots = NormalizeLots(symbol,CheckMarginAndNormalizeLotSize(symbol,lots,BidAskPrice,SLprice,AccountFreeMargin())); 
  }
  Print("... done - lotsize finally adjusted to "+DoubleToStr(lots,MarketInfo(symbol,MODE_DIGITS))+" ...");
  
 return(lots);//everything ok now, hopefully ... ;)
}//double FreeMarginCheck(string symbol,int ordertype,double lots) { 

bool CheckAccountFreeMargin(string symbol,int ordertype,double lots) {
 if (ordertype==OP_BUYSTOP || ordertype==OP_BUYLIMIT) ordertype=OP_BUY;
 if (ordertype==OP_SELLSTOP || ordertype==OP_SELLLIMIT) ordertype=OP_SELL;
  if ( ((AccountStopoutMode()==1) && (AccountFreeMarginCheck(symbol,ordertype,lots) > AccountStopoutLevel()))
  || ( (AccountStopoutMode()==0)  && (((AccountFreeMarginCheck(symbol,ordertype,lots)/AccountEquity())*100) > AccountStopoutLevel()))) return(true);//everything seems to be ok
   else return(false);
}//bool CheckAccountFreeMargin(string symbol,int ordertype,double lots) {

double CheckMarginAndNormalizeLotSize(string symbol,double lots,double BidAskPrice,double SLprice,double accBalance) {
//----
 lots = NormalizeLots(symbol,lots);
 
 double SLpips =(MathAbs(BidAskPrice - SLprice))/ MarketInfo(symbol,MODE_POINT);
   
 double ls = MarketInfo(symbol,MODE_LOTSTEP);
 double MarginRequired = MarketInfo(symbol,MODE_MARGINREQUIRED);
 //double accBalance = AccountFreeMargin();
 // fix tickvalue for extremely rare occasion when a change in ticksize leads to a change in tickvalue, source: http://forum.mql4.com/29781
 double tickValueReliable = MarketInfo(symbol,MODE_TICKVALUE) * MarketInfo(symbol,MODE_POINT) / MarketInfo(symbol,MODE_TICKSIZE);
  //Print("checkMarginAndNormalizeLotSize() - checking free margin (currency="+AccountCurrency()+"): free margin required for "+DoubleToStr(lots,3)+" lots: "+DoubleToStr(lots * MarginRequired,2)+" | for SL: "+DoubleToStr(lots * SLpips * PointValuePerLot(symbol),2)+" = total: "+DoubleToStr(lots * MarginRequired+lots * SLpips * PointValuePerLot(symbol),2)+" | current free margin: "+DoubleToStr(AccountFreeMargin(),2)+"");
  if (accBalance < lots * SLpips * tickValueReliable + lots * MarginRequired)
  //old: if (accBalance < lots * SLpips * PointValuePerLot(symbol) + lots * MarginRequired) // do we have enough money for that trade?
  { // if not, try to decrease lots:  
    if (lots>MarketInfo(symbol,MODE_MAXLOT)) lots=MarketInfo(symbol,MODE_MAXLOT);//saves time ...
   while (accBalance < (lots * SLpips * tickValueReliable) + (lots * MarginRequired))
    {
     lots = lots - ls;
     lots = NormalizeLots(symbol,lots);
    }
  }
//----
 //if (lots <= 0.0) lots = -1;
 if (lots <= 0.0) lots = MarketInfo(symbol,MODE_MINLOT);//return the minimum if everything other fails ...
 return(lots);
}//double CheckMarginAndNormalizeLotSize(string symbol,double lots,double BidAskPrice,double SLprice,double accBalance) {

//end freemargincheck
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//+------------------------------------------------------------------+
