//extern bool   use_TL         = true;
extern string TL_Name          = "GRID";
extern int WIDTH            = 15;


extern int    INCREMENT        = 10;
extern double LOTS             = 0.1;
extern int    LEVELS           = 3; 
extern double MAX_LOTS         = 99;
extern int    MAGIC            = 1803;
extern bool   CONTINUE         = true;
extern bool   MONEY_MANAGEMENT = false;
extern int    RISK_RATIO       = 2;
extern bool   USE_ENTRY_TIME   = false;
extern int    ENTRY_TIME_A     = 0;
extern int    ENTRY_TIME_B     = 0;
extern bool   USE_EXIT_TIME    = false;
extern int    EXIT_TIME        = 0;
extern double ENTRY_PRICE      = 0;
extern int    SLIPPAGE         = 5;
extern int    MULTIPLIER       = 1;
extern double EPSILON          = 5;
extern int    MONEY_PROFIT     = 0;
//-------------------------------------------------------------------------------------------------
bool _useProfitTarget=false;
bool _usePartialProfitTarget=false;
int  _targetIncrement = 50;
int  _firstTarget = 20;
bool _enter = true;
int  _nextTP;
bool _isFirstTime = true;
//-------------------------------------------------------------------------------------------------

double nadditionalVolume;
int init()
{
	double minLot = MarketInfo( Symbol(), MODE_MINLOT );
	double stopLevel = MarketInfo( Symbol(), MODE_STOPLEVEL );
	double spread = MarketInfo( Symbol(), MODE_SPREAD );

	INCREMENT = MathMax( INCREMENT * MULTIPLIER, 1 + stopLevel + spread );
	SLIPPAGE *= MULTIPLIER;
	EPSILON *= MULTIPLIER;
	if ( MONEY_MANAGEMENT )
		LOTS = NormalizeDouble( AccountBalance() * AccountLeverage() / 1000000 * RISK_RATIO, 0 ) * minLot;

	_targetIncrement *= MULTIPLIER;
	_firstTarget *= MULTIPLIER;
	_nextTP = _firstTarget;
	
	return (0);
}
//-------------------------------------------------------------------------------------------------
int deinit()
{
	return (0);
}

string trend="no Trade",slopetrend,znote;
//int sR;
int mtp,DistancePrice;
double sR;
double a,b,p,BuyPrice,SellPrice,LinePrice,ppoint;
double TL1,TL2,MIDL;
double slopeRange,MaxSR;
int nINCREMENT,wwidth;
string LineStep="start";
double prc0;
double nTop, nBot,nTime,cekP2;
double nnTop,nnBot;
double lp1,lp2,xlp1,xlp2;
datetime ld1,ld2,xld1,xld2;
bool xx;
string xtime,sym,isFound;
int maxTrade,maxIncr;
double maxAddVol,maxLossRun;
//-------------------------------------------------------------------------------------------------
int start()
{
//nnnn
	Comment(
		"mGRID EXPERT ADVISOR ver 2.3",
//		"\nqTime = ",qTime,
		"\nFX Acc Server: ",      AccountServer(),
		"\nDate: ",               Month(), "-", Day(), "-", Year(), " Server Time: ", Hour(), ":", Minute(), ":", Seconds(),
//		"\nProfit : ",             DoubleToStr(CheckProfits( LOTS, OP_SELL, true, initialPrice ),2),
//		"\nTP : ",                 DoubleToStr(profitTarget,2),
//		"\nmax Loss in Run : ",   DoubleToStr(maxLossRun,2),
		"\nMinimum Lot Sizing: ", MarketInfo( Symbol(), MODE_MINLOT ),
		"\nAccount Balance: $",   AccountBalance(),
		"\nSymbol: ",             Symbol(),
		"\nPrice: ",              NormalizeDouble( Bid, 4 ),
		"\nPip Spread: ",         MarketInfo( Symbol(), MODE_SPREAD ),
		"\nIncrement: ",          INCREMENT,
		"\nLots: ",               LOTS,
		"\nLevels: ",             LEVELS,
//		"\nadditionalVolume  : " , DoubleToStr(nadditionalVolume,2),
//		"\nmaxAddVol  : " , DoubleToStr(maxAddVol,2),
//		"\nmaxTrade   : ",             maxTrade,
//		"\nLineStep: ",           LineStep,
//		"\ntrend: ",             trend,
		"\nTL_Name: ",             TL_Name, "  ", isFound

		
		
		);
		
//-----  awal
sym=Symbol();
if(Digits==2 || Digits == 4) { mtp=1; ppoint=Point; }
      if(Digits==3 || Digits == 5) { mtp=10; ppoint=Point*10; }
      wwidth=WIDTH*mtp;
      
if ( (USE_ENTRY_TIME && Hour() < ENTRY_TIME_A ) || (USE_EXIT_TIME && Hour() > EXIT_TIME) )
xx=false;  else  xx=true;

if( (!USE_ENTRY_TIME||
      (USE_ENTRY_TIME && (Hour()==ENTRY_TIME_A || Hour()==ENTRY_TIME_B))) &&
		(!USE_EXIT_TIME || (USE_EXIT_TIME && Hour() < EXIT_TIME)) )
   xtime="InHour";
else xtime="OffHour";   			 


if(ENTRY_PRICE>0)      trend="go"; 
else
if(ENTRY_PRICE==0)  
   {  
      if(LineStep=="start") {
         if(ObjectFind(TL_Name) == 0)
            {  isFound="Found";
               lp1=ObjectGet(TL_Name, OBJPROP_PRICE1);
               lp2=ObjectGet(TL_Name, OBJPROP_PRICE2);
               xlp1=lp1; xlp2=lp2;
         
               ld1=ObjectGet(TL_Name, OBJPROP_TIME1);
               ld2=ObjectGet(TL_Name, OBJPROP_TIME2);
               xld1=lp1; xld2=lp2;    
         
               SetObject("top", ld1, lp1+wwidth*Point , ld2, lp2+wwidth*Point, LightBlue);
               SetObject("bot", ld1, lp1-wwidth*Point , ld2, lp2-wwidth*Point, PaleVioletRed);
       
               cekP2= NormalizeDouble(ObjectGetValueByShift(TL_Name,2),Digits);
               nTop = NormalizeDouble(ObjectGetValueByShift("top",0),Digits);
               nBot = NormalizeDouble(ObjectGetValueByShift("bot",0),Digits);
               LineStep="next";
            }
         else  isFound="not Found";
      }

   if(LineStep=="next")
      {   cekP2= NormalizeDouble(ObjectGetValueByShift(TL_Name,2),Digits);
          nTop = NormalizeDouble(ObjectGetValueByShift("top",0),Digits);
          nBot = NormalizeDouble(ObjectGetValueByShift("bot",0),Digits);
          xtrend(); 
   
         //if(xx)// && nnTop==nTop && nnBot==nBot ) 
         if(xtime=="InHour")
            {  if(iClose(sym,0,0)<nTop && iClose(sym,0,0)>nBot)  
                  { LineStep="next2";  trend="go";  LineStep="next2";}
               else     trend="no Trade";    
            }
      }

   if(trend=="go") { if(jmlOrder()>0)trend="Trade On"; }
   if(trend=="Trade On") 
      { if(jmlOrder()==0)
          { trend="no Trade"; LineStep="next"; Print("back to Next");}
      }

   if(LineStep=="next2" || LineStep=="next" )
      {  if( (lp1!=ObjectGet(TL_Name, OBJPROP_PRICE1)) ||
            (cekP2!= NormalizeDouble(ObjectGetValueByShift(TL_Name,2),Digits))
            )
            {  if(ObjectFind("top") == 0) { ObjectDelete("top"); nTop=0; nnTop=10;}
               if(ObjectFind("bot") == 0) { ObjectDelete("bot"); nBot=0; nnBot=10; }
               lp1=0;  lp2=0; xlp1=0; xlp2=0; ld1=0; ld2=0; xld1=0; xld2=0;
            
               if(ObjectFind(TL_Name) == 0)
                  {  isFound="Found";  
                     lp1=ObjectGet(TL_Name, OBJPROP_PRICE1);
                     lp2=ObjectGet(TL_Name, OBJPROP_PRICE2);
                     xlp1=lp1; xlp2=lp2;
                     ld1=ObjectGet(TL_Name, OBJPROP_TIME1);
                     ld2=ObjectGet(TL_Name, OBJPROP_TIME2);
                     xld1=lp1; xld2=lp2;    
                     SetObject("top", ld1, lp1+wwidth*Point , ld2, lp2+wwidth*Point, LightBlue);
                     SetObject("bot", ld1, lp1-wwidth*Point , ld2, lp2-wwidth*Point, PaleVioletRed);
                   
                     cekP2= NormalizeDouble(ObjectGetValueByShift(TL_Name,2),Digits);
                     nTop = NormalizeDouble(ObjectGetValueByShift("top",0),Digits);
                     nBot = NormalizeDouble(ObjectGetValueByShift("bot",0),Digits);
                     LineStep="next";
                  }    
                else  isFound="not Found";  
            }
     }

   }
//----------------------------------------




	int i, pipsLot, total, ticket, profit, buyGoalProfit, sellGoalProfit;
	double profitTarget = INCREMENT * 2, buyGoal, sellGoal, spread = (Ask - Bid) / Point, initialPrice, additionalVolume;

	if ( INCREMENT < MarketInfo(Symbol(), MODE_STOPLEVEL ) + spread )
		INCREMENT = 1 + MarketInfo( Symbol(), MODE_STOPLEVEL ) + spread;
	
	if ( MONEY_MANAGEMENT )
		LOTS = NormalizeDouble( AccountBalance() * AccountLeverage() / 1000000 * RISK_RATIO, 0 ) * MarketInfo( Symbol(), MODE_MINLOT );
	
	if ( LOTS < MarketInfo( Symbol(), MODE_MINLOT ) )
	{
		Print( "Not Enough Free Margin to begin" );
		return (0);
	}

	for ( i = 1; i < LEVELS; i++ )
		pipsLot += i * INCREMENT;
	
	double totalProfit = 0;
	for ( i = 0; i < OrdersTotal(); i++ )
	{
		OrderSelect( i, SELECT_BY_POS, MODE_TRADES );
		if ( OrderMagicNumber() == MAGIC && OrderSymbol() == Symbol() )
		{
			total++;
			totalProfit += OrderProfit();
			if ( initialPrice == 0 ) 
				initialPrice = StrToDouble( OrderComment() );
			if ( _usePartialProfitTarget && _useProfitTarget && OrderType() < 2 )
			{
				double val = GetPipValue( OrderOpenPrice(), OrderType() );
				TakeProfit( val, OrderTicket() );
			}
		}
	}

	// close all open and pending positions when sertain profit is reached and start again	
	if ( MONEY_PROFIT > 0 && totalProfit >= MONEY_PROFIT )
	{
		Print( "$", MONEY_PROFIT, " profit reached. Closing all orders." );
		EndSession();
		return (0);
	}
	
	
//------------------------------------------------------------------------------
bool qTime=( (!USE_ENTRY_TIME || 
              (USE_ENTRY_TIME && (Hour() == ENTRY_TIME_A || Hour() == ENTRY_TIME_B) )
			    && (!USE_EXIT_TIME || (USE_EXIT_TIME && Hour() < EXIT_TIME))) );
		
	
if(total<1 && _enter) {  
   if(AccountFreeMargin()<(100*LOTS) ) {  Print("Not enough free margin to begin"); return(0);}
		
	if(qTime && trend=="go") {
		
		// if ENTRY_PRICE is defined and it's not the current one, then wait till ENTRY_PRICE is reached
		if (_isFirstTime && ENTRY_PRICE>0 && MathAbs(ENTRY_PRICE-Ask)>EPSILON*Point) return(0);
	
		// - Open Check - Start Cycle
		if ( _isFirstTime )         initialPrice = ENTRY_PRICE;
		if ( initialPrice == 0 )    initialPrice = Ask;
		sellGoal = initialPrice - (LEVELS + 1) * INCREMENT * Point;
		buyGoal = initialPrice + (LEVELS + 1) * INCREMENT * Point;


            for(i=0; i<=LEVELS; i++ )
			{  OrderSend( Symbol(), OP_BUYSTOP, LOTS, initialPrice + i * INCREMENT * Point,
					SLIPPAGE, sellGoal, buyGoal, DoubleToStr( initialPrice, Digits ), MAGIC, 0 );
				OrderSend(  Symbol(),  OP_SELLSTOP, LOTS,  initialPrice - i * INCREMENT * Point,
					SLIPPAGE, buyGoal + spread * Point, sellGoal + spread * Point, DoubleToStr( initialPrice, Digits ),
					MAGIC, 0 );
			}
   	_isFirstTime = false;
			// initial setup done - all channels are set up
	}
}
else 
	{  // We have open Orders
		total = OrdersHistoryTotal();
		for ( i = 0; i < total; i++ )
		{
			OrderSelect( i, SELECT_BY_POS, MODE_HISTORY );
			if( OrderSymbol() == Symbol() && OrderMagicNumber() == MAGIC && 
			      StrToDouble(OrderComment()) == initialPrice)
			{  EndSession();  return (0); }
		}
		
		if ( _useProfitTarget && CheckProfits( LOTS, OP_SELL, true, initialPrice ) > profitTarget )
		{
			EndSession();
			return(0);
		}

		buyGoal = initialPrice + INCREMENT * (LEVELS + 1) * Point;
		sellGoal = initialPrice - INCREMENT * (LEVELS + 1) * Point;
		buyGoalProfit = CheckProfits( LOTS, OP_BUY, false, initialPrice );
		sellGoalProfit = CheckProfits( LOTS, OP_SELL, false, initialPrice );
		
		// - Increment Lots Buy
		if ( buyGoalProfit < profitTarget )
		{
			for( i = 1; i <= LEVELS && buyGoalProfit < profitTarget; i++ )
			{
				if ( Ask <= (initialPrice + (i * INCREMENT - MarketInfo( Symbol(), MODE_STOPLEVEL)) * Point) )
				{
					additionalVolume = CollapseOrders( initialPrice + i * INCREMENT * Point, sellGoal, buyGoal );
					nadditionalVolume=additionalVolume;
					ticket = OrderSend( Symbol(), OP_BUYSTOP, i * LOTS + additionalVolume,
						                  initialPrice + i * INCREMENT * Point, SLIPPAGE,
						                  sellGoal, buyGoal, DoubleToStr( initialPrice, Digits ),
						                  MAGIC, 0 );
				}
				if ( ticket > 0 )
					buyGoalProfit += LOTS * (buyGoal - initialPrice - i * INCREMENT * Point) / Point;
			}
		}

		// - Increment Lots Sell		
		if ( sellGoalProfit < profitTarget )
		{
			for ( i = 1; i <= LEVELS && sellGoalProfit < profitTarget; i++ )
			{
				if ( Bid >= (initialPrice - (i * INCREMENT - MarketInfo( Symbol(), MODE_STOPLEVEL )) * Point) )
				{
					additionalVolume = CollapseOrders( initialPrice - i * INCREMENT * Point, buyGoal + spread * Point, sellGoal + spread * Point );
					nadditionalVolume=additionalVolume;
					ticket = OrderSend( Symbol(), OP_SELLSTOP, i * LOTS + additionalVolume,
						                  initialPrice - i * INCREMENT * Point, SLIPPAGE,
						                  buyGoal + spread * Point, sellGoal + spread * Point,
						                  DoubleToStr( initialPrice, Digits ), MAGIC, 0 );
				}
				if ( ticket > 0 )
					sellGoalProfit += LOTS * (initialPrice - i * INCREMENT * Point - sellGoal - spread * Point) / Point;
			}
		}
	}


if(jmlOrder()>maxTrade) maxTrade=jmlOrder();
if(nadditionalVolume>maxAddVol) maxAddVol=nadditionalVolume;
if(CheckProfits( LOTS, OP_SELL, true, initialPrice )<maxLossRun)  
   maxLossRun=CheckProfits( LOTS, OP_SELL, true, initialPrice );

	return(0);
}
//-------------------------------------------------------------------------------------------------
// Removes all pending orders that have price, stoploss & takeprofit equal to given values.
// Returns total volume of removed orders.
double CollapseOrders( double price, double stopLoss, double takeProfit )
{
	int count = OrdersTotal();
	double totalVolume = 0;
	for ( int i = 0; i < count; i++ )
	{
		OrderSelect( i, SELECT_BY_POS, MODE_TRADES );
		if ( OrderSymbol() == Symbol() 
			&& OrderMagicNumber() == MAGIC 
			&& OrderType() > 1
			&& MathAbs( OrderOpenPrice() - price ) < 0.0001
			&& MathAbs( OrderStopLoss() - stopLoss  ) < 0.0001
			&& MathAbs( OrderTakeProfit() - takeProfit ) < 0.0001 )
		{
			totalVolume += OrderLots();
			OrderDelete( OrderTicket() );
		}
	}
	return (totalVolume);
}
//-------------------------------------------------------------------------------------------------
int CheckProfits( double lots, int goal, bool current, double initialPrice )
{
	int i, profit;
	if ( current )
	{
		//return current profit
		for ( i = 0; i < OrdersTotal(); i++ )
		{
			OrderSelect( i, SELECT_BY_POS, MODE_TRADES );
			if ( OrderSymbol() == Symbol() && StrToDouble(OrderComment()) == initialPrice )
			{
				if ( OrderType() == OP_BUY )
					profit += (Bid - OrderOpenPrice()) / Point * OrderLots() / lots;
				if ( OrderType() == OP_SELL) 
					profit += (OrderOpenPrice() - Ask) / Point * OrderLots() / lots;
			}
		}
		return (profit);
	}
	else
	{
		if ( goal == OP_BUY )
		{
			for( i = 0; i < OrdersTotal(); i++ )
			{
				OrderSelect( i, SELECT_BY_POS, MODE_TRADES );
				if ( OrderSymbol() == Symbol() && StrToDouble(OrderComment()) == initialPrice )
				{
					if ( OrderType() == OP_BUY )
						profit += (OrderTakeProfit() - OrderOpenPrice()) / Point * OrderLots() / lots;
					if ( OrderType() == OP_SELL ) 
						profit -= (OrderStopLoss() - OrderOpenPrice()) / Point * OrderLots() / lots;
					if ( OrderType() == OP_BUYSTOP ) 
						profit += (OrderTakeProfit() - OrderOpenPrice()) / Point * OrderLots() / lots;
				}
			}
			return (profit);
		}
		else
		{
			for ( i = 0; i < OrdersTotal(); i++ )
			{
				OrderSelect( i, SELECT_BY_POS, MODE_TRADES );
				if ( OrderSymbol() == Symbol() && StrToDouble(OrderComment()) == initialPrice )
				{
					if ( OrderType() == OP_BUY )
						profit -= (OrderOpenPrice() - OrderStopLoss()) / Point * OrderLots() / lots;
					if( OrderType() == OP_SELL )
						profit += (OrderOpenPrice() - OrderTakeProfit()) / Point * OrderLots() / lots;
					if ( OrderType() == OP_SELLSTOP )
						profit += (OrderOpenPrice() - OrderTakeProfit()) / Point * OrderLots() / lots;              
				}
			}
			return (profit);
		}
	}
}
//-------------------------------------------------------------------------------------------------
bool EndSession()
{
	int total = OrdersTotal();
	for ( int i = 0; i < total; i++ )
	{
		Sleep( 3000 );
		OrderSelect( i, SELECT_BY_POS, MODE_TRADES );
		if ( OrderSymbol() == Symbol() && OrderType() > 1 )
			OrderDelete( OrderTicket() );
		else if ( OrderSymbol() == Symbol() && OrderType() == OP_BUY ) 
			OrderClose( OrderTicket(), OrderLots(), Bid, SLIPPAGE );
		else if ( OrderSymbol() == Symbol() && OrderType() == OP_SELL )
			OrderClose( OrderTicket(), OrderLots(), Ask, SLIPPAGE );
	}
	
	if ( !CONTINUE )
		_enter = false;
		
	return (true);
}
//-------------------------------------------------------------------------------------------------
double GetPipValue( double ord, int dir )
{
	double val;
	RefreshRates();
	if ( dir == 1)
		val = (NormalizeDouble( ord, Digits ) - NormalizeDouble( Ask, Digits ));
	else
		val = (NormalizeDouble( Bid, Digits ) - NormalizeDouble( ord, Digits ));
	val = val / Point;
	return (val);   
}
//-------------------------------------------------------------------------------------------------
void TakeProfit( int currentPips, int ticket )
{
	if ( OrderSelect( ticket, SELECT_BY_TICKET ) )
	{
		if ( currentPips >= _nextTP && currentPips < (_nextTP + _targetIncrement) )
		{
			if ( OrderType() == 1 )
			{
				if ( OrderClose( ticket, MAX_LOTS, Ask, 3 ) )
					_nextTP += _targetIncrement;
				else
					Print( "Error closing order : ", GetLastError() ); 
			} 
			else
			{
				if ( OrderClose( ticket, MAX_LOTS, Bid, 3 ) )
					_nextTP += _targetIncrement;
				else
					Print( "Error closing order : ",GetLastError() );
			}        
		}
	}
}
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 
void SetObject(string name,datetime T1,double P1,datetime T2,double P2,color clr)
  {
   if(ObjectFind(name) == -1)
     {
       ObjectCreate(name, OBJ_TREND, 0, T1, P1, T2, P2);
       ObjectSet(name, OBJPROP_COLOR, clr);
       ObjectSet(name, OBJPROP_STYLE, STYLE_DOT);
     }
   else
     {
       ObjectSet(name, OBJPROP_TIME1, T1);
       ObjectSet(name, OBJPROP_PRICE1, P1);
       ObjectSet(name, OBJPROP_TIME2, T2);
       ObjectSet(name, OBJPROP_PRICE2, P2);
       ObjectSet(name, OBJPROP_COLOR, clr);
       ObjectSet(name, OBJPROP_STYLE, STYLE_DOT);
     } 
  }
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
void xtrend()
{  

if(!xx) trend="Not in Trading Hour"; 
nnTop=nTop;
nnBot=nBot; 
     
}
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 
     
int jmlOrder()
 { int gantung;
   for (int i=0;i<OrdersTotal();i++)
     { OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
      if (OrderSymbol() == sym && OrderCloseTime()==0) 
         {  if(OrderType()==OP_SELLSTOP || OrderType()==OP_BUYSTOP ||
               OrderType()==OP_SELL || OrderType()==OP_BUY)
               { if(OrderMagicNumber()==MAGIC) 
                  gantung++;
               }  
         }
      }
   return(gantung);
 } 
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 
int jmlStopBuy()
 { int gantung;
   for (int i=0;i<OrdersTotal();i++)
     { OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
      if (OrderSymbol() == sym && OrderCloseTime()==0) 
         {  if(OrderType()==OP_BUYSTOP )
               { if(OrderMagicNumber()==MAGIC ) 
                  gantung++;
               }   
         }
      }
   return(gantung);
 }
 
        
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

int jmlStopSell()
 { int gantung;
   for (int i=0;i<OrdersTotal();i++)
     { OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
      if (OrderSymbol() == sym && OrderCloseTime()==0) 
         {  if(OrderType()==OP_SELLSTOP)
               { if(OrderMagicNumber()==MAGIC) 
                  gantung++;
               }  
         }
      }
   return(gantung);
 } 
 
//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 

