//+------------------------------------------------------------------------------+//
//)   ____  _  _  ____  ____  ____  ____  __  __    __      ___  _____  __  __   (//
//)  ( ___)( \/ )(  _ \(  _ \( ___)( ___)(  \/  )  /__\    / __)(  _  )(  \/  )  (//
//)   )__)  )  (  )(_) ))   / )__)  )__)  )    (  /(__)\  ( (__  )(_)(  )    (   (//
//)  (__)  (_/\_)(____/(_)\_)(____)(____)(_/\/\_)(__)(__)()\___)(_____)(_/\/\_)  (//
//)   http://fxdreema.com                              Copyright 2015, fxDreema  (//
//+------------------------------------------------------------------------------+//
#property copyright ""
#property link      "https://fxdreema.com"

/************************************************************************************************************************/
// +------------------------------------------------------------------------------------------------------------------+ //
// |                       INPUT PARAMETERS, GLOBAL VARIABLES, CONSTANTS, IMPORTS and INCLUDES                        | //
// |                      System and Custom variables and other definitions used in the project                       | //
// +------------------------------------------------------------------------------------------------------------------+ //
/************************************************************************************************************************/

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// System constants (project settings) //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
#define PROJECT_ID           "mt4-1344"
#define VIRTUAL_STOPS_ENABLED    false // true or false
#define VIRTUAL_STOPS_TIMEOUT 0//--
#define USE_EMERGENCY_STOPS  "no"   // "yes" to use emergency (hard stops) when virtual stops are in use. "always" to use EMERGENCY_STOPS_ADD as emergency stops when there is no virtual stop.
#define EMERGENCY_STOPS_REL  0       // Use 0 to disable hard stops when virtual stops are enabled. Use a value >=0 to automatically set hard stops with virtual. Example: if 2 is used, then hard stops will be 2 times bigger than virtual ones.
#define EMERGENCY_STOPS_ADD  0       // Add pips to relative size of emergency stops (hard stops)
//--
#define ON_TRADE_REALTIME    0 //
#define ON_TIMER_PERIOD   60        // Timer event period (in seconds)
//--
#define ENABLE_EVENT_TICK  1 // "Tick"  event: 1 - enable, 0 - disable
#define ENABLE_EVENT_TRADE 1 // "Trade" event: 1 - enable, 0 - disable
#define ENABLE_EVENT_TIMER 0 // "Timer" event: 1 - enable, 0 - disable
///////

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// System constants (predefined constants) //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
#define TLOBJPROP_TIME1 801
#define OBJPROP_TL_PRICE_BY_SHIFT 802
#define OBJPROP_TL_SHIFT_BY_PRICE 803
#define OBJPROP_FIBOVALUE 804
#define OBJPROP_FIBOPRICEVALUE 805
#define OBJPROP_BARSHIFT1 807
#define OBJPROP_BARSHIFT2 808
#define OBJPROP_BARSHIFT3 809
#define SEL_CURRENT 0
#define SEL_INITIAL 1

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// Project global variables, includes, imports //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
extern int MagicStart=0; // Magic Start (MagicNumber=MagicStart+Group#)

//VVVVVVVVVVVVVVVVVVVVVVVVV//
// System global variables //
//^^^^^^^^^^^^^^^^^^^^^^^^^//
int FXD_CURRENT_FUNCTION_ID=0;
double FXD_MILS_INIT_END=0;
bool FXD_FIRST_TICK_PASSED=false;
bool FXD_BREAK=false;
bool FXD_CONTINUE=false;
bool FXD_CHART_IS_OFFLINE = false;
bool FXD_ONTIMER_TAKEN = false;
bool FXD_ONTIMER_TAKEN_IN_MILLISECONDS = false;
double FXD_ONTIMER_TAKEN_TIME = 0;
bool USE_VIRTUAL_STOPS = VIRTUAL_STOPS_ENABLED;

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// Global variables used as On-Off property for fxDreema blocks //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
bool block1=true; // For each Closed Trade
bool block2=true; // Delete pending orders&nbsp;
bool block3=true; // Check trades count&nbsp;
bool block4=true; // Check pending orders count&nbsp;
bool block5=true; // check how it was closed
bool block6=true; // (on trade) Trade closed&nbsp;
bool block7=true; // Delete pending orders&nbsp;
bool block8=true; // (on trade) Trade closed&nbsp;
bool block9=true; // Delete pending orders&nbsp;
bool block10=true; // (on trade) Trade closed&nbsp;
bool block11=true; // Delete pending orders&nbsp;

/************************************************************************************************************************/
// +------------------------------------------------------------------------------------------------------------------+ //
// |                                                 EVENT FUNCTIONS                                                  | //
// |                           These are the main functions that controls the whole project                           | //
// +------------------------------------------------------------------------------------------------------------------+ //
/************************************************************************************************************************/

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// This function is executed once when the program starts //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
int OnInit()
{
	Comment("");

	if (IsOptimization()) {
		// According to http://docs.mql4.com/runtime/testing: During optimization, working with graphical objects is not supported.
		USE_VIRTUAL_STOPS = false;
	}
	TimeAtStart("set"); // Set local and server time at start
	AccountBalanceAtStart(); // Set balance at start
	DrawSpreadInfo();
	DrawStatus("waiting for tick...");

	if (MQLInfoInteger(MQL_PROGRAM_TYPE) == PROGRAM_EXPERT)
	{
		FXD_CHART_IS_OFFLINE = ChartGetInteger(0, CHART_IS_OFFLINE);
	}

	if (MQLInfoInteger(MQL_PROGRAM_TYPE) != PROGRAM_SCRIPT)
	{
		if (FXD_CHART_IS_OFFLINE == true || (ENABLE_EVENT_TRADE == 1 && ON_TRADE_REALTIME == 1))
		{
			FXD_ONTIMER_TAKEN = true;
			EventSetMillisecondTimer(1);
		}
		if (ENABLE_EVENT_TIMER) {
			OnTimerSet(ON_TIMER_PERIOD);
		}
	}

	FXD_MILS_INIT_END = GetTickCount();
	FXD_FIRST_TICK_PASSED = false; // reset is needed when changing inputs

	return(INIT_SUCCEEDED);
}

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// This function is executed on every incoming tick //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
// This is the native MQL4 on-tick function
void OnTick()
{
	if (FXD_FIRST_TICK_PASSED==false)
	{
		FXD_FIRST_TICK_PASSED=true;
		DrawStatus("working");
	}

	//-- special system actions
	DrawSpreadInfo();
	TicksData(""); // Collect ticks (if needed)
	if (USE_VIRTUAL_STOPS) {VirtualStopsDriver();}
	ExpirationDriver();
	if (ENABLE_EVENT_TRADE) {OnTradeListener();}

	// Main beginning on the graph
	block3();



	TicksFromStart(true);
	return;
}

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// This function is executed on trade events - open, close, modify //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
void EventTrade()
{
	block6();

	OnTradeQueue(-1);
}

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// This function is executed on a period basis //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
void OnTimer()
{
	//-- to simulate ticks in offline charts, Timer is used instead of infinite loop
	//-- the next function checks for changes in price and calls OnTick() manually
	if (FXD_CHART_IS_OFFLINE && RefreshRates()) {
		OnTick();
	}
	if (ON_TRADE_REALTIME == 1) {
		OnTradeListener();
	}

	static int t0 = 0;
	int t = 0;
	bool ok = false;

	if (FXD_ONTIMER_TAKEN)
	{
		if (FXD_ONTIMER_TAKEN_TIME > 0)
		{
			if (FXD_ONTIMER_TAKEN_IN_MILLISECONDS == true)
			{
				t = GetTickCount();
			}
			else
			{
				t = TimeLocal();
			}
			if ((t - t0) >= FXD_ONTIMER_TAKEN_TIME)
			{
				t0 = t;
				ok = true;
			}
		}

		if (ok == false) {
			return;
		}
	}


}

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// This function is executed once when the program ends //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
void OnDeinit(const int reason)
{
	//-- if Timer was set, kill it here
	EventKillTimer();

	if (MQLInfoInteger(MQL_TESTER)) {
		Print("Backtested in "+DoubleToStr((GetTickCount()-FXD_MILS_INIT_END)/1000, 2)+" seconds");
		Print("Average ticks per second: "+DoubleToStr(TicksFromStart()/(GetTickCount()-FXD_MILS_INIT_END),0));
	}

	DrawStatus("stopped");
	if (MQLInfoInteger(MQL_PROGRAM_TYPE) == PROGRAM_EXPERT)
	{
		switch(UninitializeReason())
		{
			case REASON_PROGRAM		: Print("Expert Advisor self terminated"); break;
			case REASON_REMOVE		: Print("Expert Advisor removed from the chart"); break;
			case REASON_RECOMPILE	: Print("Expert Advisorhas been recompiled"); break;
			case REASON_CHARTCHANGE	: Print("Symbol or chart period has been changed"); break;
    		case REASON_CHARTCLOSE	: Print("Chart has been closed"); break;
    		case REASON_PARAMETERS	: Print("Input parameters have been changed by a user"); break;
    		case REASON_ACCOUNT		: Print("Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings"); break;
			case REASON_TEMPLATE	: Print("A new template has been applied"); break;
			case REASON_INITFAILED	: Print("OnInit() handler has returned a nonzero value"); break;
			case REASON_CLOSE		: Print("Terminal has been closed"); break;
		}
	}
}

/************************************************************************************************************************/
// +------------------------------------------------------------------------------------------------------------------+ //
// |                                   FUNCTIONS THAT REPRESENTS BLOCKS IN FXDREEMA                                   | //
// |                                    Each block is represented as function here                                    | //
// +------------------------------------------------------------------------------------------------------------------+ //
/************************************************************************************************************************/

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #1 (For each Closed Trade) //
void block1(int _parent_=0)
{
	if (block1==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=1;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string OrdersScope="group"; // Group mode
	string OrdersGroup=""; // Group # (empty=Default)
	string SymbolScope="symbol"; // Market mode
	string SYMBOL=CurrentSymbol(); // Market (empty=Current)
	string BuysOrSells="both"; // Filter by type
	string LoopDirection="newest-to-oldest"; // Loop direction
	int LoopSkip=0; // Skip "n" history trades
	int LoopEvery=0; // Every "n" trade
	int LoopLimit=1; // Not more than "n" history trades
	int PassEnd=0; // Second output
	
	///////////////
	// Main code //
	///////////////
	
	int saved_ticket=attrTicketInLoop(); // This ticket number will be reloaded at the end of this loop, so if we are in another overlapping loop - it will continue using it's last used ticket number
	
	int TotalOrders=OrdersHistoryTotal();
	int count=0; int skip=-1;
	int pos=0;
	int every=0;
	
	if (LoopDirection=="newest-to-oldest")
	{
	   for (pos=TotalOrders-1; pos>=0; pos--) {
	      if (FXD_CONTINUE==true) {FXD_BREAK=false; FXD_CONTINUE=false;}
	      else if (FXD_BREAK==true) {FXD_BREAK=false; FXD_CONTINUE=false; break;}
	      if (OrderSelect(pos,SELECT_BY_POS,MODE_HISTORY)) {
	         if (FilterOrderBy(OrdersScope,OrdersGroup, SymbolScope,SYMBOL, BuysOrSells)) {
	            skip++;
	            if (LoopSkip<=skip && (count<LoopLimit || LoopLimit==0)) {
	               if (LoopEvery>0) {every++; if (every<LoopEvery) {continue;} else {every=0;}}
	               count++;
	               attrTicketInLoop(attrTicket());
	               block5(1);
	               if (count==LoopLimit) break;
	}  }  }  }  }
	else if (LoopDirection=="oldest-to-newest")
	{
	   for (pos=0; pos<TotalOrders; pos++) {
	      if (FXD_CONTINUE==true) {FXD_BREAK=false; FXD_CONTINUE=false;}
	      else if (FXD_BREAK==true) {FXD_BREAK=false; FXD_CONTINUE=false; break;}
	      if (OrderSelect(pos,SELECT_BY_POS,MODE_HISTORY)) {
	         if (FilterOrderBy(OrdersScope,OrdersGroup, SymbolScope,SYMBOL, BuysOrSells)) {
	            skip++;
	            if (LoopSkip<=skip && (count<LoopLimit || LoopLimit==0)) {
	               if (LoopEvery>0) {every++; if (every<LoopEvery) {continue;} else {every=0;}}
	               count++;
	               attrTicketInLoop(attrTicket());
	               block5(1);
	               if (count==LoopLimit) break;
	}  }  }  }  }
	
	attrTicketInLoop(saved_ticket); // Reloading Ticket number from the overlapping loop (if any)
	
	FXD_BREAK=false; FXD_CONTINUE=false;
	
	if (PassEnd==0 || (PassEnd==1 && count>0) || (PassEnd==2 && count==0)) {
	   /* Yellow output */
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #2 (Delete pending orders&nbsp;) //
void block2(int _parent_=0)
{
	if (block2==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=2;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string OrdersScope="group"; // Group mode
	string OrdersGroup=""; // Group # (empty=Default)
	string SymbolScope="symbol"; // Market mode
	string SYMBOL=CurrentSymbol(); // Market (empty=Current)
	string BuysOrSells="both"; // Filter by type
	string LimitsOrStops="both"; // Filter by pending type
	double Slippage=3; // Slippage
	color ArrowColor=DeepPink; // Arrow color
	
	///////////////
	// Main code //
	///////////////
	
	for (int pos=OrdersTotal()-1; pos>=0; pos--) {
	   if (OrderSelect(pos,SELECT_BY_POS,MODE_TRADES)) {
	      if (FilterOrderBy(OrdersScope,OrdersGroup, SymbolScope,SYMBOL, BuysOrSells, LimitsOrStops, 1)) {
	         DeleteOrder(attrTicket(),ArrowColor);
	      }
	   }
	}
	
	/* Orange output */
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #3 (Check trades count&nbsp;) //
void block3(int _parent_=0)
{
	if (block3==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=3;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	int CompareCount=0; // Orders count
	string GroupMode="group"; // Group mode
	string Group=""; // Group # (empty=Default)
	string MarketMode="market"; // Market mode
	string Market=CurrentSymbol(); // Market (empty=Current)
	string BuysOrSells="both"; // Filter by type
	string LimitsOrStops="both"; // Filter by pending type
	
	///////////////
	// Main code //
	///////////////
	
	int count=0;
	for (int pos=OrdersTotal()-1; pos>=0; pos--) {
	   if (OrderSelect(pos,SELECT_BY_POS, MODE_TRADES)) {
	      if (FilterOrderBy(GroupMode,Group, MarketMode,Market, BuysOrSells)) {
	         count++;
	      }
	   }
	}
	
	if (count==CompareCount) {block4(3);} else {/* Yellow output */}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #4 (Check pending orders count&nbsp;) //
void block4(int _parent_=0)
{
	if (block4==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=4;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	int CompareCount=1; // Orders count
	string GroupMode="group"; // Group mode
	string Group=""; // Group # (empty=Default)
	string MarketMode="market"; // Market mode
	string Market=CurrentSymbol(); // Market (empty=Current)
	string BuysOrSells="both"; // Filter by type
	string LimitsOrStops="both"; // Filter by pending type
	
	///////////////
	// Main code //
	///////////////
	
	int count=0;
	for (int pos=OrdersTotal()-1; pos>=0; pos--) {
	   if (OrderSelect(pos,SELECT_BY_POS, MODE_TRADES)) {
	      if (FilterOrderBy(GroupMode,Group, MarketMode,Market, BuysOrSells, LimitsOrStops, 1)) {
	         count++;
	      }
	   }
	}
	
	if (count==CompareCount) {block1(4);} else {/* Yellow output */}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #5 (check how it was closed) //
void block5(int _parent_=0)
{
	if (block5==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=5;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	int ModeClosed=3; // it was closed by...
	
	///////////////
	// Main code //
	///////////////
	
	bool next = false;
	
	if (ModeClosed==0) {
	   next=true;
	}
	else
	{
	   if (attrType() <= OP_SELL)
	   { //-- trade
	      if ((ModeClosed==1 || ModeClosed==2) && StringFind(attrComment(), "[sl]")!=-1) {next=true;}  
	      else if ((ModeClosed==1 || ModeClosed==3)  && StringFind(attrComment(), "[tp]")!=-1) {next=true;}
	      else if (ModeClosed==4 && (StringFind(attrComment(), "[sl]")==-1 && StringFind(attrComment(), "[sl]")==-1)) {next=true;}
	   }
	   else
	   { //-- pending order
	      return;
	   }
	}
	if (next==true) {block2(5);} else {/* Yellow output */}
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #6 ((on trade) Trade closed&nbsp;) //
void block6(int _parent_=0)
{
	if (block6==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=6;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string GroupMode="group"; // Group mode
	string Group=""; // Group # (empty=Default)
	string MarketMode="market"; // Market mode
	string Market=CurrentSymbol(); // Market (empty=Current)
	string BuysOrSells="both"; // Filter by type
	string CloseMode="tp"; // Closed by
	int ClosePartialMode=1; // Closed how
	
	///////////////
	// Main code //
	///////////////
	
	string close_type="nosltp";
	
	if (StringFind(e_attrComment(), "[sl]") >= 0) {close_type = "sl";}
	else if (StringFind(e_attrComment(), "[tp]") >= 0) {close_type = "tp";}
	else
	{
	   double cp = e_attrClosePrice();
	   if (e_attrType() == OP_BUY)
	   {
	      if (e_attrStopLoss() > cp) {close_type = "sl";}
	      else if (e_attrTakeProfit() < cp) {close_type = "tp";}
	   }
	   else if (e_attrType() == OP_SELL)
	   {
	      if (e_attrStopLoss() < cp) {close_type = "sl";}
	      else if (e_attrTakeProfit() > cp) {close_type = "tp";}
	   }
	   
	}
	
	if (
	   e_Reason()=="closed"
	   &&
	   (FilterEventTrade(GroupMode,Group,MarketMode,Market,BuysOrSells))
	   &&
	   ((CloseMode=="") || (CloseMode==close_type) || (CloseMode=="sltp" && (close_type=="sl" || close_type=="tp")))
	   &&
	   (
	      (ClosePartialMode==0)
	      || (ClosePartialMode==1 && e_attrTicket() == attrTicketParent(e_attrTicket())) // fully closed
	      || (ClosePartialMode==1 && e_attrTicket() == attrTicketChild(e_attrTicket())) // fully closed when partially closed -> the trade is gone
	      || (ClosePartialMode==2 && e_attrTicket() != attrTicketParent(e_attrTicket()) && e_attrTicket() != attrTicketChild(e_attrTicket())) // partially closed
	   )
	)
	{block7(6);} else {/* Yellow output */}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #7 (Delete pending orders&nbsp;) //
void block7(int _parent_=0)
{
	if (block7==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=7;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string OrdersScope="group"; // Group mode
	string OrdersGroup=""; // Group # (empty=Default)
	string SymbolScope="symbol"; // Market mode
	string SYMBOL=CurrentSymbol(); // Market (empty=Current)
	string BuysOrSells="both"; // Filter by type
	string LimitsOrStops="both"; // Filter by pending type
	double Slippage=4; // Slippage
	color ArrowColor=DeepPink; // Arrow color
	
	///////////////
	// Main code //
	///////////////
	
	for (int pos=OrdersTotal()-1; pos>=0; pos--) {
	   if (OrderSelect(pos,SELECT_BY_POS,MODE_TRADES)) {
	      if (FilterOrderBy(OrdersScope,OrdersGroup, SymbolScope,SYMBOL, BuysOrSells, LimitsOrStops, 1)) {
	         DeleteOrder(attrTicket(),ArrowColor);
	      }
	   }
	}
	
	block8(7);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #8 ((on trade) Trade closed&nbsp;) //
void block8(int _parent_=0)
{
	if (block8==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=8;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string GroupMode="group"; // Group mode
	string Group=""; // Group # (empty=Default)
	string MarketMode="market"; // Market mode
	string Market=CurrentSymbol(); // Market (empty=Current)
	string BuysOrSells="both"; // Filter by type
	string CloseMode="tp"; // Closed by
	int ClosePartialMode=1; // Closed how
	
	///////////////
	// Main code //
	///////////////
	
	string close_type="nosltp";
	
	if (StringFind(e_attrComment(), "[sl]") >= 0) {close_type = "sl";}
	else if (StringFind(e_attrComment(), "[tp]") >= 0) {close_type = "tp";}
	else
	{
	   double cp = e_attrClosePrice();
	   if (e_attrType() == OP_BUY)
	   {
	      if (e_attrStopLoss() > cp) {close_type = "sl";}
	      else if (e_attrTakeProfit() < cp) {close_type = "tp";}
	   }
	   else if (e_attrType() == OP_SELL)
	   {
	      if (e_attrStopLoss() < cp) {close_type = "sl";}
	      else if (e_attrTakeProfit() > cp) {close_type = "tp";}
	   }
	   
	}
	
	if (
	   e_Reason()=="closed"
	   &&
	   (FilterEventTrade(GroupMode,Group,MarketMode,Market,BuysOrSells))
	   &&
	   ((CloseMode=="") || (CloseMode==close_type) || (CloseMode=="sltp" && (close_type=="sl" || close_type=="tp")))
	   &&
	   (
	      (ClosePartialMode==0)
	      || (ClosePartialMode==1 && e_attrTicket() == attrTicketParent(e_attrTicket())) // fully closed
	      || (ClosePartialMode==1 && e_attrTicket() == attrTicketChild(e_attrTicket())) // fully closed when partially closed -> the trade is gone
	      || (ClosePartialMode==2 && e_attrTicket() != attrTicketParent(e_attrTicket()) && e_attrTicket() != attrTicketChild(e_attrTicket())) // partially closed
	   )
	)
	{block9(8);} else {/* Yellow output */}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #9 (Delete pending orders&nbsp;) //
void block9(int _parent_=0)
{
	if (block9==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=9;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string OrdersScope="group"; // Group mode
	string OrdersGroup=""; // Group # (empty=Default)
	string SymbolScope="symbol"; // Market mode
	string SYMBOL=CurrentSymbol(); // Market (empty=Current)
	string BuysOrSells="both"; // Filter by type
	string LimitsOrStops="both"; // Filter by pending type
	double Slippage=4; // Slippage
	color ArrowColor=DeepPink; // Arrow color
	
	///////////////
	// Main code //
	///////////////
	
	for (int pos=OrdersTotal()-1; pos>=0; pos--) {
	   if (OrderSelect(pos,SELECT_BY_POS,MODE_TRADES)) {
	      if (FilterOrderBy(OrdersScope,OrdersGroup, SymbolScope,SYMBOL, BuysOrSells, LimitsOrStops, 1)) {
	         DeleteOrder(attrTicket(),ArrowColor);
	      }
	   }
	}
	
	block10(9);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #10 ((on trade) Trade closed&nbsp;) //
void block10(int _parent_=0)
{
	if (block10==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=10;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string GroupMode="group"; // Group mode
	string Group=""; // Group # (empty=Default)
	string MarketMode="market"; // Market mode
	string Market=CurrentSymbol(); // Market (empty=Current)
	string BuysOrSells="both"; // Filter by type
	string CloseMode="tp"; // Closed by
	int ClosePartialMode=1; // Closed how
	
	///////////////
	// Main code //
	///////////////
	
	string close_type="nosltp";
	
	if (StringFind(e_attrComment(), "[sl]") >= 0) {close_type = "sl";}
	else if (StringFind(e_attrComment(), "[tp]") >= 0) {close_type = "tp";}
	else
	{
	   double cp = e_attrClosePrice();
	   if (e_attrType() == OP_BUY)
	   {
	      if (e_attrStopLoss() > cp) {close_type = "sl";}
	      else if (e_attrTakeProfit() < cp) {close_type = "tp";}
	   }
	   else if (e_attrType() == OP_SELL)
	   {
	      if (e_attrStopLoss() < cp) {close_type = "sl";}
	      else if (e_attrTakeProfit() > cp) {close_type = "tp";}
	   }
	   
	}
	
	if (
	   e_Reason()=="closed"
	   &&
	   (FilterEventTrade(GroupMode,Group,MarketMode,Market,BuysOrSells))
	   &&
	   ((CloseMode=="") || (CloseMode==close_type) || (CloseMode=="sltp" && (close_type=="sl" || close_type=="tp")))
	   &&
	   (
	      (ClosePartialMode==0)
	      || (ClosePartialMode==1 && e_attrTicket() == attrTicketParent(e_attrTicket())) // fully closed
	      || (ClosePartialMode==1 && e_attrTicket() == attrTicketChild(e_attrTicket())) // fully closed when partially closed -> the trade is gone
	      || (ClosePartialMode==2 && e_attrTicket() != attrTicketParent(e_attrTicket()) && e_attrTicket() != attrTicketChild(e_attrTicket())) // partially closed
	   )
	)
	{block11(10);} else {/* Yellow output */}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #11 (Delete pending orders&nbsp;) //
void block11(int _parent_=0)
{
	if (block11==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=11;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string OrdersScope="group"; // Group mode
	string OrdersGroup=""; // Group # (empty=Default)
	string SymbolScope="symbol"; // Market mode
	string SYMBOL=CurrentSymbol(); // Market (empty=Current)
	string BuysOrSells="both"; // Filter by type
	string LimitsOrStops="both"; // Filter by pending type
	double Slippage=4; // Slippage
	color ArrowColor=DeepPink; // Arrow color
	
	///////////////
	// Main code //
	///////////////
	
	for (int pos=OrdersTotal()-1; pos>=0; pos--) {
	   if (OrderSelect(pos,SELECT_BY_POS,MODE_TRADES)) {
	      if (FilterOrderBy(OrdersScope,OrdersGroup, SymbolScope,SYMBOL, BuysOrSells, LimitsOrStops, 1)) {
	         DeleteOrder(attrTicket(),ArrowColor);
	      }
	   }
	}
	
	/* Orange output */
}


/************************************************************************************************************************/
// +------------------------------------------------------------------------------------------------------------------+ //
// |                                                  API FUNCTIONS                                                   | //
// |                                 System and Custom functions used in the program                                  | //
// +------------------------------------------------------------------------------------------------------------------+ //
/************************************************************************************************************************/

// System functions
double AccountBalanceAtStart()
{
   // This function MUST be run once at pogram's start
	static double memory=0;
   if (memory==0) {memory=AccountBalance();}
   return(memory);
}
int ArraySearch(double &array[], double value)
{
   static bool founded; founded=false;
   static int index;    index=0;
   static int size;
   size=ArraySize(array);
   
   if (size>0)
   {
   	for (int i=0; i<size; i++)
      {
         if (array[i]==value)
         {
            founded=true;
            index=i;
            break;
         }  
   	}
   }

   if (founded==true) {return (index);} else {return (-1);}
}
int ArraySearch(int &array[], int value)
{
   static bool founded; founded=false;
   static int index;    index=0;
   static int size;
   size=ArraySize(array);
   
   if (size>0)
   {
      for (int i=0; i<size; i++)
      {
         if (array[i]==value)
         {
            founded=true;
            index=i;
            break;
         }  
   	}
   }

   if (founded==true) {return (index);} else {return (-1);}
}
int ArraySearch(string &array[], string value)
{
   static bool founded; founded=false;
   static int index;    index=0;
   static int size;
   size=ArraySize(array);
   
   if (size>0)
   {
      for (int i=0; i<size; i++)
      {
         if (array[i]==value)
         {
            founded=true;
            index=i;
            break;
         }  
   	}
   }

   if (founded==true) {return (index);} else {return (-1);}
}
bool ArrayStripKey(double &array[], double key)
{
   static bool stripped; stripped=false;
   static int size;
   size = ArraySize(array);
   if (size>0)
   {
      int i=0; int x=0;
      for (i=0; i<size; i++)
      {
         if (i!=key)
         {
            array[x]=array[i];
            x++;
         } else {
            stripped=true;  
         }
      }
      ArrayResize(array,x);
   }
   return (stripped);
}
bool ArrayStripKey(int &array[], int key)
{
   static bool stripped; stripped=false;
   static int size;
   size = ArraySize(array);
   if (size>0)
   {
      int i=0; int x=0;
      for (i=0; i<size; i++)
      {
         if (i!=key)
         {
            array[x]=array[i];
            x++;
         } else {
            stripped=true;  
         }
      }
      ArrayResize(array,x);
   }
   return (stripped);
}
bool ArrayStripKey(string &array[], string key)
{
   static bool stripped; stripped=false;
   static int size;
   size = ArraySize(array);
   if (size>0)
   {
      int i=0; int x=0;
      for (i=0; i<size; i++)
      {
         if (i!=key)
         {
            array[x]=array[i];
            x++;
         } else {
            stripped=true;  
         }
      }
      ArrayResize(array,x);
   }
   return (stripped);
}
double attrClosePrice(string sel="")
{
   return(OrderClosePrice());
}
string attrComment(string sel="")
{
   return(OrderComment());
}
double attrCommission(string sel="")
{
   if (sel=="e" || sel=="event") {return(e_attrCommission());}
   return(OrderCommission());
}
datetime attrExpiration(string sel="")
{
   return(OrderExpiration());
}
double attrLots(string sel="")
{
   return(OrderLots());
}
int attrMagicNumber(string sel="")
{
   return(OrderMagicNumber());
}
double attrOpenPrice(string sel="")
{
   return(OrderOpenPrice());
}
double attrProfit(string sel="")
{
   return(OrderProfit());
}
double attrStopLoss()
{
   if (USE_VIRTUAL_STOPS) {return(VirtualStopsDriver("get sl",OrderTicket()));}
   return(OrderStopLoss());
}
string attrSymbol(string sel="")
{
   return(OrderSymbol());
}
double attrTakeProfit()
{
   if (USE_VIRTUAL_STOPS) {return(VirtualStopsDriver("get tp",OrderTicket()));}
   return(OrderTakeProfit());
}
int attrTicket()
{
   return(OrderTicket());
}
int attrTicketChild(int ticket)
{
   int pos, total, retval=0;

   if (!OrderSelect(ticket,SELECT_BY_TICKET)) {retval=ticket;}
   
   /*
   //-- check if trade is added to volume ----------------------------
   if (retval==0) {
      int p_pos=StringFind(attrComment(), "[p=");
      if (p_pos >= 0) {
         string ptag=StringSubstr(attrComment(),p_pos);
         ptag=StringSubstr(ptag,0,StringFind(ptag,"]")+1);
         retval=StrToInteger(StringSubstr(ptag,3,-1));
      }
   }
   */
   //-- check if trade is partially closed (in trades) ---------------
   if (retval==0) {
      double OP=OrderOpenPrice();
      double OT=OrderOpenTime();
      string S =OrderSymbol();
      int M    =OrderMagicNumber();
      int T    =OrderType(); 
      int L    =OrderLots();
      int D    =MarketInfo(S,MODE_DIGITS);
      
      total=OrdersTotal();
      for (pos=total-1; pos>=0; pos--) {
         if (OrderSelect(pos,SELECT_BY_POS,MODE_TRADES))
         {
            if (OrderOpenTime()<OT) {
               break;
            }
            if (
               OrderTicket()!=ticket
               && (OrderSymbol()==S)
               && (OrderMagicNumber()==M)
               && (OrderType()==T)
               && (NormalizeDouble(OrderOpenPrice(),D)==NormalizeDouble(OP,D))
               && (OrderOpenTime()==OT)
               )
            {
               retval=OrderTicket();
               break;
            }
         }
      }
   }
   //-- still nothing found - search in history trades now -----------
   if (retval==0) {
      total=OrdersHistoryTotal();
      for (pos=total-1; pos>=0; pos--) {
         if (OrderSelect(pos,SELECT_BY_POS,MODE_HISTORY))
         {
            if (OrderOpenTime()<OT) {
               break;
            }
            if (
               OrderTicket()!=ticket
               && (OrderSymbol()==S)
               && (OrderMagicNumber()==M)
               && (OrderType()==T)
               && (NormalizeDouble(OrderOpenPrice(),D)==NormalizeDouble(OP,D))
               && (OrderOpenTime()==OT)
               )
            {
               retval=OrderTicket();
               break;
            }
         }
      }
   }
   
   if (retval<ticket) {retval=0;}

   OrderSelect(ticket,SELECT_BY_TICKET);
   if (retval>0) {
      return(retval);
   }
   else {
      return(ticket);
   }
}
int attrTicketInLoop(int ticket=0)
{
	static int t;
   if (ticket>0) {t=ticket;}
   return(t);
}
int attrTicketParent(int ticket)
{
   int pos, total, retval=0;
   static int parents_idx[];
   static int parents[];

   //-- if parent ticket is known, return it ----------------------------
   int size=ArraySize(parents_idx);
   int idx=-1;
   if (size>0)
   {
      for (int i=size-1; i>=0; i--) {
         if (parents_idx[i]==ticket) {
            idx=i;
            break;
         }  
      }
   }
   if (idx>-1) {
         retval=parents[idx];
   }
   else {
      if (!OrderSelect(ticket,SELECT_BY_TICKET)) {retval=ticket;}
      
      //-- check if trade is added to volume ----------------------------
      if (retval==0) {
         int p_pos=StringFind(attrComment(), "[p=");
         if (p_pos >= 0) {
            string ptag=StringSubstr(attrComment(),p_pos);
            ptag=StringSubstr(ptag,0,StringFind(ptag,"]")+1);
            retval=StrToInteger(StringSubstr(ptag,3,-1));
         }
      }
      //-- check if trade is partially closed (in trades) ---------------
      if (retval==0) {
         double OP=OrderOpenPrice();
         double OT=OrderOpenTime();
         string S =OrderSymbol();
         int M    =OrderMagicNumber();
         int T    =OrderType(); 
         int L    =OrderLots();
         int D    =MarketInfo(S,MODE_DIGITS);
         
         total=OrdersTotal();
         for (pos=total-1; pos>=0; pos--) {
            if (OrderSelect(pos,SELECT_BY_POS,MODE_TRADES))
            {
               if (OrderOpenTime()<OT) {
                  break;
               }
               if (
                  OrderTicket()!=ticket
                  && (OrderSymbol()==S)
                  && (OrderMagicNumber()==M)
                  && (OrderType()==T)
                  && (NormalizeDouble(OrderOpenPrice(),D)==NormalizeDouble(OP,D))
                  && (OrderOpenTime()==OT)
                  )
               {
                  retval=OrderTicket();
               }
            }
         }
      }
      //-- still nothing found - search in history trades now -----------
      if (retval==0) {
         total=OrdersHistoryTotal();
         for (pos=total-1; pos>=0; pos--) {
            if (OrderSelect(pos,SELECT_BY_POS,MODE_HISTORY))
            {
               if (OrderOpenTime()<OT) {
                  break;
               }
               if (
                  OrderTicket()!=ticket
                  && (OrderSymbol()==S)
                  && (OrderMagicNumber()==M)
                  && (OrderType()==T)
                  && (NormalizeDouble(OrderOpenPrice(),D)==NormalizeDouble(OP,D))
                  && (OrderOpenTime()==OT)
                  )
               {
                  retval=OrderTicket();
               }
            }
         }
      }
      if (retval>0) {
         size=ArraySize(parents_idx);
         ArrayResize(parents_idx,size+1);
         ArrayResize(parents,size+1);
         parents_idx[size]=ticket;
         parents[size]=retval;
      }
   }
   OrderSelect(ticket,SELECT_BY_TICKET);
   if (retval>0) {
      return(retval);
   }
   else {
      return(ticket);
   }
}
double attrType(string sel="")
{
   return(OrderType());
}
double ChartEventParameterDouble(int cmd=0,double inp=-1) {static double mem=-1; if(cmd==1){mem=inp;} return(mem);}
double ChartEventParameterLong(int cmd=0,double inp=-1) {static double mem=-1; if(cmd==1){mem=inp;} return(mem);}
string ChartEventParameterString(int cmd=0,string inp="") {static string mem=""; if(cmd==1){mem=inp;} return(mem);}
int ChartEventType(int cmd=0,int inp=-1) {static int mem=-1; if(cmd==1){mem=inp;} return(mem);}
int CheckForTradingError(int error_code=-1, string msg_prefix="")
{
   // return 0 -> no error
   // return 1 -> overcomable error
   // return 2 -> fatal error
   
	if (error_code<0) {
      error_code=GetLastError();  
	}
   
   int retval=0;
   static int tryouts=0;
   
   //-- error check -----------------------------------------------------
   switch(error_code)
   {
      //-- no error
      case 0:
         retval=0;
         break;
      //-- overcomable errors
      case 1: // No error returned
         RefreshRates();
         retval=1;
         break;
      case 4: //ERR_SERVER_BUSY
         if (msg_prefix!="") {Print(StringConcatenate(msg_prefix,": ",ErrorMessage(error_code),". Retrying.."));}
         Sleep(1000);
         RefreshRates();
         retval=1;
         break;
      case 6: //ERR_NO_CONNECTION
         if (msg_prefix!="") {Print(StringConcatenate(msg_prefix,": ",ErrorMessage(error_code),". Retrying.."));}
         while(!IsConnected()) {Sleep(100);}
         while(IsTradeContextBusy()) {Sleep(50);}
         RefreshRates();
         retval=1;
         break;
      case 128: //ERR_TRADE_TIMEOUT
         if (msg_prefix!="") {Print(StringConcatenate(msg_prefix,": ",ErrorMessage(error_code),". Retrying.."));}
         RefreshRates();
         retval=1;
         break;
      case 129: //ERR_INVALID_PRICE
         if (msg_prefix!="") {Print(StringConcatenate(msg_prefix,": ",ErrorMessage(error_code),". Retrying.."));}
         while(RefreshRates()==false) {Sleep(1);}
         retval=1;
         break;
      case 130: //ERR_INVALID_STOPS
         if (msg_prefix!="") {Print(StringConcatenate(msg_prefix,": ",ErrorMessage(error_code),". Waiting for a new tick to retry.."));}
         while(RefreshRates()==false) {Sleep(1);}
         retval=1;
         break;
      case 135: //ERR_PRICE_CHANGED
         if (msg_prefix!="") {Print(StringConcatenate(msg_prefix,": ",ErrorMessage(error_code),". Waiting for a new tick to retry.."));}
         while(RefreshRates()==false) {Sleep(1);}
         retval=1;
         break;
      case 136: //ERR_OFF_QUOTES
         if (msg_prefix!="") {Print(StringConcatenate(msg_prefix,": ",ErrorMessage(error_code),". Waiting for a new tick to retry.."));}
         while(RefreshRates()==false) {Sleep(1);}
         retval=1;
         break;
      case 137: //ERR_BROKER_BUSY
         if (msg_prefix!="") {Print(StringConcatenate(msg_prefix,": ",ErrorMessage(error_code),". Retrying.."));}
         Sleep(1000);
         retval=1;
         break;
      case 138: //ERR_REQUOTE
         if (msg_prefix!="") {Print(StringConcatenate(msg_prefix,": ",ErrorMessage(error_code),". Waiting for a new tick to retry.."));}
         while(RefreshRates()==false) {Sleep(1);}
         retval=1;
         break;
      case 142: //This code should be processed in the same way as error 128.
         if (msg_prefix!="") {Print(StringConcatenate(msg_prefix,": ",ErrorMessage(error_code),". Retrying.."));}
         RefreshRates();
         retval=1;
         break;
      case 143: //This code should be processed in the same way as error 128.
         if (msg_prefix!="") {Print(StringConcatenate(msg_prefix,": ",ErrorMessage(error_code),". Retrying.."));}
         RefreshRates();
         retval=1;
         break;
      /*case 145: //ERR_TRADE_MODIFY_DENIED
         if (msg_prefix!="") {Print(StringConcatenate(msg_prefix,": ",ErrorMessage(error_code),". Waiting for a new tick to retry.."));}
         while(RefreshRates()==false) {Sleep(1);}
         return(1);
      */
      case 146: //ERR_TRADE_CONTEXT_BUSY
         if (msg_prefix!="") {Print(StringConcatenate(msg_prefix,": ",ErrorMessage(error_code),". Retrying.."));}
         while(IsTradeContextBusy()) {Sleep(50);}
         RefreshRates();
         retval=1;
         break;
      //-- critical errors
      default:
         if (msg_prefix!="") {Print(StringConcatenate(msg_prefix,": ",ErrorMessage(error_code)));}
         retval=2;
         break;
   }

   if (retval==0) {tryouts=0;}
   else if (retval==1) {
      tryouts++;
      if (tryouts>=10) {
         tryouts=0;
         retval=2;
      } else {
         Print("retry #"+tryouts+" of 10");
      }
   }
   
   return(retval);
}
bool CloseTrade(int ticket, double slippage=0, color arrowcolor=CLR_NONE)
{
   bool success=false;
   if (!OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) {return(false);}
   
   while(true)
   {
      //-- wait if needed -----------------------------------------------
      WaitTradeContextIfBusy();
      //-- close --------------------------------------------------------
      success=OrderClose(ticket,attrLots(),attrClosePrice(),slippage*PipValue(attrSymbol()),arrowcolor);
      if (success==true) {
         if (USE_VIRTUAL_STOPS) {
            VirtualStopsDriver("clear",ticket);
         }
         RegisterEvent("trade");
         return(true);
      }
      //-- errors -------------------------------------------------------
      int erraction=CheckForTradingError(GetLastError(), "Closing trade #"+ticket+" error");
      switch(erraction)
      {
         case 0: break;    // no error
         case 1: continue; // overcomable error
         case 2: break;    // fatal error
      }
      break;
   }
   return(false);
}
string CurrentSymbol(string symbol="")
{
   static string memory="";
   if (symbol!="") {memory=symbol;} else
   if (memory=="") {memory=Symbol();}
   return(memory);
}
bool DeleteOrder(int ticket, color arrowcolor)
{
   bool success=false;
   if (!OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) {return(false);}
   
   while(true)
   {
      //-- wait if needed -----------------------------------------------
      WaitTradeContextIfBusy();
      //-- delete -------------------------------------------------------
      success=OrderDelete(ticket,arrowcolor);
      if (success==true) {
         if (USE_VIRTUAL_STOPS) {
            VirtualStopsDriver("clear",ticket);
         }
         RegisterEvent("trade");
         return(true);
      }
      //-- error check --------------------------------------------------
      int erraction=CheckForTradingError(GetLastError(), "Deleting order #"+ticket+" error");
      switch(erraction)
      {
         case 0: break;    // no error
         case 1: continue; // overcomable error
         case 2: break;    // fatal error
      }
      break;
   }
   return(false);
}
void DrawSpreadInfo()
{
   static bool allow_draw = true;
   if (allow_draw==false) {return;}
   if (MQLInfoInteger(MQL_TESTER) && !MQLInfoInteger(MQL_VISUAL_MODE)) {allow_draw=false;} // Allowed to draw only once in testing mode

   static bool passed         = false;
   static double max_spread   = 0;
   static double min_spread   = EMPTY_VALUE;
   static double avg_spread   = 0;
   static double avg_add      = 0;
   static double avg_cnt      = 0;

   double current_spread = (SymbolInfoDouble(Symbol(),SYMBOL_ASK)-SymbolInfoDouble(Symbol(),SYMBOL_BID))/(CustomPoint(Symbol()));
   if (current_spread > max_spread) {max_spread = current_spread;}
   if (current_spread < min_spread) {min_spread = current_spread;}
   
   avg_cnt++;
   avg_add     = avg_add + current_spread;
   avg_spread  = avg_add / avg_cnt;

   int x=0; int y=0;
   string name;

   // create objects
   if (passed == false)
   {
      passed=true;
      
      name="fxd_spread_current_label";
      if (ObjectFind(0, name)==-1) {
         ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
         ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x+1);
         ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y+1);
         ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
         ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 18);
         ObjectSetInteger(0, name, OBJPROP_COLOR, clrDarkOrange);
         ObjectSetString(0, name, OBJPROP_FONT, "Arial");
         ObjectSetString(0, name, OBJPROP_TEXT, "Spread:");
      }
      name="fxd_spread_max_label";
      if (ObjectFind(0, name)==-1) {
         ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
         ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x+148);
         ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y+17);
         ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
         ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 7);
         ObjectSetInteger(0, name, OBJPROP_COLOR, clrOrangeRed);
         ObjectSetString(0, name, OBJPROP_FONT, "Arial");
         ObjectSetString(0, name, OBJPROP_TEXT, "max:");
      }
      name="fxd_spread_avg_label";
      if (ObjectFind(0, name)==-1) {
         ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
         ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x+148);
         ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y+9);
         ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
         ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 7);
         ObjectSetInteger(0, name, OBJPROP_COLOR, clrDarkOrange);
         ObjectSetString(0, name, OBJPROP_FONT, "Arial");
         ObjectSetString(0, name, OBJPROP_TEXT, "avg:");
      }
      name="fxd_spread_min_label";
      if (ObjectFind(0, name)==-1) {
         ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
         ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x+148);
         ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y+1);
         ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
         ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 7);
         ObjectSetInteger(0, name, OBJPROP_COLOR, clrGold);
         ObjectSetString(0, name, OBJPROP_FONT, "Arial");
         ObjectSetString(0, name, OBJPROP_TEXT, "min:");
      }
      name="fxd_spread_current";
      if (ObjectFind(0, name)==-1) {
         ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
         ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x+93);
         ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y+1);
         ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
         ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 18);
         ObjectSetInteger(0, name, OBJPROP_COLOR, clrDarkOrange);
         ObjectSetString(0, name, OBJPROP_FONT, "Arial");
         ObjectSetString(0, name, OBJPROP_TEXT, "0");
      }
      name="fxd_spread_max";
      if (ObjectFind(0, name)==-1) {
         ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
         ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x+173);
         ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y+17);
         ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
         ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 7);
         ObjectSetInteger(0, name, OBJPROP_COLOR, clrOrangeRed);
         ObjectSetString(0, name, OBJPROP_FONT, "Arial");
         ObjectSetString(0, name, OBJPROP_TEXT, "0");
      }
      name="fxd_spread_avg";
      if (ObjectFind(0, name)==-1) {
         ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
         ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x+173);
         ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y+9);
         ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
         ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 7);
         ObjectSetInteger(0, name, OBJPROP_COLOR, clrDarkOrange);
         ObjectSetString(0, name, OBJPROP_FONT, "Arial");
         ObjectSetString(0, name, OBJPROP_TEXT, "0");
      }
      name="fxd_spread_min";
      if (ObjectFind(0, name)==-1) {
         ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
         ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x+173);
         ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y+1);
         ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
         ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 7);
         ObjectSetInteger(0, name, OBJPROP_COLOR, clrGold);
         ObjectSetString(0, name, OBJPROP_FONT, "Arial");
         ObjectSetString(0, name, OBJPROP_TEXT, "min:");
      }
   }
   
   ObjectSetString(0, "fxd_spread_current", OBJPROP_TEXT, DoubleToStr(current_spread,2));
   ObjectSetString(0, "fxd_spread_max", OBJPROP_TEXT, DoubleToStr(max_spread,2));
   ObjectSetString(0, "fxd_spread_avg", OBJPROP_TEXT, DoubleToStr(avg_spread,2));
   ObjectSetString(0, "fxd_spread_min", OBJPROP_TEXT, DoubleToStr(min_spread,2));
}
string DrawStatus(string text="")
{
   static string memory;
   if (text=="") {
      return(memory);
   }
   
   static bool passed = false;
   int x=210; int y=0;
   string name;

   //-- draw the objects once
   if (passed == false)
   {
      passed = true;
      name="fxd_status_title";
      ObjectCreate(0,name, OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0,name, OBJPROP_BACK, false);
      ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_LOWER);
      ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
      ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
      ObjectSetInteger(0,name, OBJPROP_XDISTANCE, x);
      ObjectSetInteger(0,name, OBJPROP_YDISTANCE, y+17);
      ObjectSetString(0,name, OBJPROP_TEXT, "Status");
      ObjectSetString(0,name, OBJPROP_FONT, "Arial");
      ObjectSetInteger(0,name, OBJPROP_FONTSIZE, 7);
      ObjectSetInteger(0,name, OBJPROP_COLOR, clrGray);
      
      name="fxd_status_text";
      ObjectCreate(0,name, OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0,name, OBJPROP_BACK, false);
      ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_LOWER);
      ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
      ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
      ObjectSetInteger(0,name, OBJPROP_XDISTANCE, x+2);
      ObjectSetInteger(0,name, OBJPROP_YDISTANCE, y+1);
      ObjectSetString(0,name, OBJPROP_FONT, "Arial");
      ObjectSetInteger(0,name, OBJPROP_FONTSIZE, 12);
      ObjectSetInteger(0,name, OBJPROP_COLOR, clrAqua);
   }

   //-- update the text when needed
   if (text != memory) {
      memory=text;
      ObjectSetString(0,"fxd_status_text", OBJPROP_TEXT, text);
   }
   
   return(text);
}
double e_attrClosePrice(bool set=false, double inp=-1) {static double mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
string e_attrComment(bool set=false, string inp="") {static string mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
double e_attrCommission(bool set=false, double inp=0) {static double mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
datetime e_attrExpiration(bool set=false, datetime inp=0) {static datetime mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
double e_attrLots(bool set=false, double inp=-1) {static double mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
int e_attrMagicNumber(bool set=false, int inp=-1) {static int mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
double e_attrOpenPrice(bool set=false, double inp=-1) {static double mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
datetime e_attrOpenTime(bool set=false, datetime inp=-1) {static datetime mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
double e_attrProfit(bool set=false, double inp=0) {static double mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
double e_attrStopLoss(bool set=false, double inp=-1) {static double mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
double e_attrSwap(bool set=false, double inp=0) {static double mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
string e_attrSymbol(bool set=false, string inp="") {static string mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
double e_attrTakeProfit(bool set=false, double inp=-1) {static double mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
int e_attrTicket(bool set=false, int inp=-1) {static int mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
int e_attrType(bool set=false, int inp=-1) {static int mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
string e_Reason(bool set=false, string inp="") {
   static string mem[];
   int queue=OnTradeQueue()-1;
   if(set==true){
      ArrayResize(mem,queue+1);
      mem[queue]=inp;
   }
   return(mem[queue]);
}
string e_ReasonDetail(bool set=false, string inp="") {static string mem[];int queue=OnTradeQueue()-1;if(set==true){ArrayResize(mem,queue+1);mem[queue]=inp;}return(mem[queue]);}
string ErrorMessage(int error_code=-1)
{
   if (error_code<0) {error_code=GetLastError();}
   string error_string="";

   switch(error_code)
     {
      //-- codes returned from trade server
      case 0:   return("");
      case 1:   error_string="No error returned"; break;
      case 2:   error_string="Common error"; break;
      case 3:   error_string="Invalid trade parameters"; break;
      case 4:   error_string="Trade server is busy"; break;
      case 5:   error_string="Old version of the client terminal"; break;
      case 6:   error_string="No connection with trade server"; break;
      case 7:   error_string="Not enough rights"; break;
      case 8:   error_string="Too frequent requests"; break;
      case 9:   error_string="Malfunctional trade operation (never returned error)"; break;
      case 64:  error_string="Account disabled"; break;
      case 65:  error_string="Invalid account"; break;
      case 128: error_string="Trade timeout"; break;
      case 129: error_string="Invalid price"; break;
      case 130: error_string="Invalid Sl or TP"; break;
      case 131: error_string="Invalid trade volume"; break;
      case 132: error_string="Market is closed"; break;
      case 133: error_string="Trade is disabled"; break;
      case 134: error_string="Not enough money"; break;
      case 135: error_string="Price changed"; break;
      case 136: error_string="Off quotes"; break;
      case 137: error_string="Broker is busy (never returned error)"; break;
      case 138: error_string="Requote"; break;
      case 139: error_string="Order is locked"; break;
      case 140: error_string="Only long trades allowed"; break;
      case 141: error_string="Too many requests"; break;
      case 145: error_string="Modification denied because order too close to market"; break;
      case 146: error_string="Trade context is busy"; break;
      case 147: error_string="Expirations are denied by broker"; break;
      case 148: error_string="Amount of open and pending orders has reached the limit"; break;
      case 149: error_string="Hedging is prohibited"; break;
      case 150: error_string="Prohibited by FIFO rules"; break;
      //-- mql4 errors
      case 4000: error_string="No error"; break;
      case 4001: error_string="Wrong function pointer"; break;
      case 4002: error_string="Array index is out of range"; break;
      case 4003: error_string="No memory for function call stack"; break;
      case 4004: error_string="Recursive stack overflow"; break;
      case 4005: error_string="Not enough stack for parameter"; break;
      case 4006: error_string="No memory for parameter string"; break;
      case 4007: error_string="No memory for temp string"; break;
      case 4008: error_string="Not initialized string"; break;
      case 4009: error_string="Not initialized string in array"; break;
      case 4010: error_string="No memory for array string"; break;
      case 4011: error_string="Too long string"; break;
      case 4012: error_string="Remainder from zero divide"; break;
      case 4013: error_string="Zero divide"; break;
      case 4014: error_string="Unknown command"; break;
      case 4015: error_string="Wrong jump"; break;
      case 4016: error_string="Not initialized array"; break;
      case 4017: error_string="dll calls are not allowed"; break;
      case 4018: error_string="Cannot load library"; break;
      case 4019: error_string="Cannot call function"; break;
      case 4020: error_string="Expert function calls are not allowed"; break;
      case 4021: error_string="Not enough memory for temp string returned from function"; break;
      case 4022: error_string="System is busy"; break;
      case 4050: error_string="Invalid function parameters count"; break;
      case 4051: error_string="Invalid function parameter value"; break;
      case 4052: error_string="String function internal error"; break;
      case 4053: error_string="Some array error"; break;
      case 4054: error_string="Incorrect series array using"; break;
      case 4055: error_string="Custom indicator error"; break;
      case 4056: error_string="Arrays are incompatible"; break;
      case 4057: error_string="Global variables processing error"; break;
      case 4058: error_string="Global variable not found"; break;
      case 4059: error_string="Function is not allowed in testing mode"; break;
      case 4060: error_string="Function is not confirmed"; break;
      case 4061: error_string="Send mail error"; break;
      case 4062: error_string="String parameter expected"; break;
      case 4063: error_string="Integer parameter expected"; break;
      case 4064: error_string="Double parameter expected"; break;
      case 4065: error_string="Array as parameter expected"; break;
      case 4066: error_string="Requested history data in update state"; break;
      case 4099: error_string="End of file"; break;
      case 4100: error_string="Some file error"; break;
      case 4101: error_string="Wrong file name"; break;
      case 4102: error_string="Too many opened files"; break;
      case 4103: error_string="Cannot open file"; break;
      case 4104: error_string="Incompatible access to a file"; break;
      case 4105: error_string="No order selected"; break;
      case 4106: error_string="Unknown symbol"; break;
      case 4107: error_string="Invalid price parameter for trade function"; break;
      case 4108: error_string="Invalid ticket"; break;
      case 4109: error_string="Trade is not allowed in the expert properties"; break;
      case 4110: error_string="Longs are not allowed in the expert properties"; break;
      case 4111: error_string="Shorts are not allowed in the expert properties"; break;
      case 4200: error_string="Object is already exist"; break;
      case 4201: error_string="Unknown object property"; break;
      case 4202: error_string="Object is not exist"; break;
      case 4203: error_string="Unknown object type"; break;
      case 4204: error_string="No object name"; break;
      case 4205: error_string="Object coordinates error"; break;
      case 4206: error_string="No specified subwindow"; break;
      case 4207: error_string="Some error in object function"; break;
      default:   error_string="Unknown error";
     }

   //if (error_code>0) {Print("("+error_code+") "+error_string);}
   error_string=StringConcatenate(error_string," ("+error_code+")");
   return(error_string);
}
void ExpirationDriver()
{
   static int last_checked_ticket;
   static int db_tickets[];
   static int db_expirations[];

   static int total; total   = OrdersTotal();
   static int size;  size    = 0;
   static int do_reset; do_reset=false;
   static string print;
   static int i;
   
   //-- check expirations and close trades
   size = ArraySize(db_tickets);
   if (size>0)
   {
      if (total==0) {
         ArrayResize(db_tickets, 0);
         ArrayResize(db_expirations, 0);
      }
      else
      {
         for (i=0; i<size; i++)
         {
            WaitTradeContextIfBusy();
            if (!OrderSelect(db_tickets[i],SELECT_BY_TICKET, MODE_TRADES)) {continue;}
            if (OrderSymbol() != Symbol()) {continue;}
            
            if (TimeCurrent() >= OrderOpenTime()+db_expirations[i]) {
               
               //-- trying to skip conflicts with the same functionality running from neighbour EA
               WaitTradeContextIfBusy();
               if (!OrderSelect(db_tickets[i],SELECT_BY_TICKET, MODE_TRADES)) {continue;}
               if (OrderCloseTime()>0) {continue;}
               
               //-- closing the trade
               if (CloseTrade(OrderTicket())) 
               {
                  print = "#"+(string)OrderTicket()+" was closed due to expiration";
                  Print(print);
                  last_checked_ticket=0;
                  do_reset = true;
                  total    = OrdersTotal();
               }
            }
         }
      }
   }
   
   //-- check the ticket of the newest trade
   if (do_reset==false && total>0)
   {
      if (OrderSelect(total-1,SELECT_BY_POS)) {
         if (OrderTicket()!=last_checked_ticket) {
            do_reset = true;
         }
      }
   }

   //-- rebuild the database of trades with expirations
   if (do_reset==true)
   {
      static string comment;
      ArrayResize(db_tickets, 0);
      ArrayResize(db_expirations, 0);
      for (int pos=0; pos<total; pos++)
      {
         if (!OrderSelect(pos,SELECT_BY_POS)) {continue;}
         last_checked_ticket = OrderTicket();

         comment = OrderComment();
         int exp_pos_begin = StringFind(comment, "[exp:");
         if (exp_pos_begin >= 0)
         {
            exp_pos_begin = exp_pos_begin+5;
            int exp_pos_end = StringFind(comment, "]", exp_pos_begin);
            if (exp_pos_end == -1) {continue;}
            
            size = ArraySize(db_tickets);
            ArrayResize(db_tickets, size+1);
            ArrayResize(db_expirations, size+1);
            db_tickets[size]     = OrderTicket();
            db_expirations[size] = StringToInteger(StringSubstr(comment, exp_pos_begin, exp_pos_end));
         }
      }
   }
}
bool FilterEventTrade(string group_mode,int group,string market_mode="market",string market="",string BuysOrSells="both", string LimitsOrStops="")
{
   static string market0="-";
   static string markets[];
   static int markets_count0=0;
   int markets_count=1;
   int i=0;
   
   if (market_mode=="all") {
      markets_count=1; // there is no matter what market is
   }
   else {
      if (market0!=market) {
         if (market=="") {
            markets_count0=1;
            ArrayResize(markets,1);
            markets[0]=Symbol();
         }
         else {
            StringExplode(",",market,markets);
            market0=market;
            markets_count0=ArraySize(markets);
            for(i=0;i<markets_count0;i++) {
               markets[i]=StringTrim(markets[i]);
               if (markets[i]=="") {markets[i]=Symbol();}
            }
         }
      }
      markets_count=markets_count0;
   }
   
   for(i=0;i<markets_count;i++) {

      if (
        (group_mode=="all" || (group_mode=="group" && e_attrMagicNumber()==(MagicStart+group)) || (group_mode=="manual" && e_attrMagicNumber()==0))
        &&
        (market_mode=="all" || markets[i]==e_attrSymbol())
        &&
        (
           (
              LimitsOrStops==""
              &&
              (
                 (BuysOrSells=="buys"  && e_attrType()==OP_BUY)
                 ||
                 (BuysOrSells=="sells" && e_attrType()==OP_SELL)
                 ||
                 (BuysOrSells=="both"  && (e_attrType()==OP_BUY || e_attrType()==OP_SELL))
              )
           )
           ||
           (
              LimitsOrStops!=""
              &&
              (
                  (
                     (BuysOrSells=="buys"  && (e_attrType()==OP_BUYSTOP || e_attrType()==OP_BUYLIMIT))
                     ||
                     (BuysOrSells=="sells" && (e_attrType()==OP_SELLSTOP || e_attrType()==OP_SELLLIMIT))
                     ||
                     (BuysOrSells=="both"  && (e_attrType()==OP_BUYSTOP || e_attrType()==OP_BUYLIMIT || e_attrType()==OP_SELLSTOP || e_attrType()==OP_SELLLIMIT))
                  )
                  &&
                  (
                     ((LimitsOrStops=="stops" || LimitsOrStops=="both") && (e_attrType()==OP_BUYSTOP || e_attrType()==OP_SELLSTOP))
                     ||
                     ((LimitsOrStops=="limits" || LimitsOrStops=="both") && (e_attrType()==OP_BUYLIMIT || e_attrType()==OP_SELLLIMIT))
                  )
               )
            )
         )
      )
      {
         return(true);
      }
   }
	return(false);
}
bool FilterOrderBy(string _group_mode="all", string _group="0", string _market_mode="all", string _market="", string _BuysOrSells="both", string _LimitsOrStops="both", int _TradesOrders=0)
{
   // TradesOrders=0 - trades only
   // TradesOrders=1 - orders only
   // TradesOrders=2 - trades and orders

   //-- db
   static string market0="-";
   static string markets[];
   static int markets_size=0;
   
   static string group0="-";
   static string groups[];
   static int groups_size=0;
   
   //-- local variables
   static bool type_pass; type_pass = false;
   static bool market_pass; market_pass = false;
   static bool group_pass; group_pass = false;
   
   static int i;
   static int type;
   
   //-- get
   static string group_mode;     group_mode = _group_mode;
   static string group;          group = _group;
   static string market_mode;    market_mode = _market_mode;
   static string market;         market = _market;
   static string BuysOrSells;    BuysOrSells = _BuysOrSells;
   static string LimitsOrStops;  LimitsOrStops = _LimitsOrStops;
   static int TradesOrders;      TradesOrders = _TradesOrders;
   
   // Trades
   type=OrderType();
   if (TradesOrders==0)
   {
      if (
            (BuysOrSells=="both"  && (type==OP_BUY || type==OP_SELL))
         || (BuysOrSells=="buys"  && type==OP_BUY)
         || (BuysOrSells=="sells" && type==OP_SELL)
         
         )
      {
         type_pass = true;
      }
   }
   // Pending orders
   else if (TradesOrders==1)
   {
      if (
            ((BuysOrSells=="buys" || BuysOrSells=="both") && (type==OP_BUYLIMIT || type==OP_BUYSTOP))
         || ((BuysOrSells=="sells" || BuysOrSells=="both") && (type==OP_SELLLIMIT || type==OP_SELLSTOP))
         )
      {
         if (
               ((LimitsOrStops=="stops" || LimitsOrStops=="both") && (type==OP_BUYSTOP || type==OP_SELLSTOP))
            || ((LimitsOrStops=="limits" || LimitsOrStops=="both") && (type==OP_BUYLIMIT || type==OP_SELLLIMIT))               
            )
         {
            type_pass = true;
         }
      }
   }
   //-- Trades and orders --------------------------------------------
   else
   {
      if (
            (BuysOrSells=="both")
         || (BuysOrSells=="buys"  && (type==OP_BUY || type==OP_BUYLIMIT || type==OP_BUYSTOP))
         || (BuysOrSells=="sells" && (type==OP_SELL || type==OP_SELLLIMIT || type==OP_SELLSTOP))
         )
      {
         type_pass = true;
      }
   }
   if (type_pass == false) {return false;}

   //-- check group
   if (group_mode=="group")
   {
      if (group0!=group)
      {
         group0=group;
         StringExplode(",",group,groups);
         groups_size = ArraySize(groups);
         for(i=0; i<groups_size; i++)
         {
            groups[i]=StringTrimRight(groups[i]);
            groups[i]=StringTrimLeft(groups[i]);
            if (groups[i]=="") {groups[i]="0";}
         }
      }
      for(i=0; i<groups_size; i++)
      {
         if (OrderMagicNumber()==(MagicStart+(int)groups[i]))
         {
            group_pass=true;
            break;
         }
      }
   }
   else if (group_mode=="all" || (group_mode=="manual" && OrderMagicNumber()==0)) {
      group_pass = true;  
   }
   if (group_pass == false) {return false;}
   
   // check market
   if (market_mode=="all") {
      market_pass=true;
      
   }
   else {
      if (market0!=market)
      {
         market0=market;
         if (market=="")
         {
            markets_size = 1;
            ArrayResize(markets,1);
            markets[0]=Symbol();
         }
         else
         {
            StringExplode(",", market,markets);
            markets_size = ArraySize(markets);
            for(i=0; i<markets_size; i++)
            {
               markets[i]=StringTrimRight(markets[i]);
               markets[i]=StringTrimLeft(markets[i]);
               if (markets[i]=="") {markets[i]=Symbol();}
            }
         }
      }
      for(i=0; i<markets_size; i++) {
         if (OrderSymbol()==markets[i]) {
            market_pass = true;
            break;
         }
      }
   }
   if (market_pass == false) {return false;}
   
   return true;
}
string GetSymbol(string symbol="")
{
   static string memory="";
   if (symbol=="") {
      if (memory=="") {memory=Symbol();}
   }
   else {memory=symbol;}
   return(memory);
}
bool OnTimerSet(double seconds)
{
   if (FXD_ONTIMER_TAKEN)
   {
      if (seconds<=0) {
         FXD_ONTIMER_TAKEN_IN_MILLISECONDS = false;
         FXD_ONTIMER_TAKEN_TIME = 0;
      }
      else if (seconds < 1) {
         FXD_ONTIMER_TAKEN_IN_MILLISECONDS = true;
         FXD_ONTIMER_TAKEN_TIME = seconds*1000; 
      }
      else {
         FXD_ONTIMER_TAKEN_IN_MILLISECONDS = false;
         FXD_ONTIMER_TAKEN_TIME = seconds;
      }
      
      return true;
   }

   if (seconds<=0) {
      EventKillTimer();
   }
   else if (seconds < 1) {
      return (EventSetMillisecondTimer((int)(seconds*1000)));  
   }
   else {
      return (EventSetTimer((int)seconds));
   }
   
   return true;
}
void OnTradeListener()
{
   if (!ENABLE_EVENT_TRADE) {return;}

   int i=-1, j=-1, k=-1; int ti=-1; int ty=-1;
   int size=-1;
   static int start_time=-1;
  
   int pos=0;
   
   if (start_time==-1) {start_time=TimeCurrent();}

   string e_reason="";
   string e_detail="";
   
   ///////
   // TRADES AND ORDERS
   int tickets_now[]; ArrayResize(tickets_now,0);
   int tn=0;
   static int    memory_ti[];
   static int    memory_ty[];
   static double memory_sl[];
   static double memory_tp[];
   static double memory_vl[];
   static bool loaded=false;
   
   int total=OrdersTotal();
   
   // initial fill of the local DB
   if (loaded==false)
   {
      loaded=true;
      for (pos=total-1; pos>=0; pos--)
      {
         if (OrderSelect(pos,SELECT_BY_POS,MODE_TRADES))
         {
            ArrayResize(memory_ti,tn+1);
            ArrayResize(memory_ty,tn+1);
            ArrayResize(memory_sl,tn+1);
            ArrayResize(memory_tp,tn+1);
            ArrayResize(memory_vl,tn+1);
            memory_ti[tn]=OrderTicket();
            memory_ty[tn]=OrderType();
            memory_sl[tn]=attrStopLoss();
            memory_tp[tn]=attrTakeProfit();
            memory_vl[tn]=OrderLots();
            tn++;
         }
      }
      return;
   }
   tn=0;
   
   bool pending_opens=false;
   
   for (pos=total-1; pos>=0; pos--)
   {
      if (OrderSelect(pos,SELECT_BY_POS,MODE_TRADES))
      {
         ArrayResize(tickets_now,tn+1);
         tickets_now[tn]=OrderTicket();
         tn++;
         
         // Trades and Orders
         i=-1; ti=-1; ty=-1; size=ArraySize(memory_ti);
         
         if (size>0)
         {
           for (i=0; i<size; i++)
           {
              if (memory_ti[i]==OrderTicket())
              {
                 if (memory_ty[i]==OrderType()) {
                    ty=OrderType();
                  }
                  else {
                     pending_opens=true;
                  }
                  ti=OrderTicket(); break;
              }
           }
         }

         // Order become a trade
         if (ti>0 && ty<0)
         {
            memory_ti[i]=OrderTicket();
            memory_ty[i]=OrderType();
           
            memory_sl[i]=attrStopLoss();
            memory_tp[i]=attrTakeProfit();
            memory_vl[i]=OrderLots();
            e_reason="new";
            e_detail="";
            break;
         }

         // New trade/order opened
         else if (ti<0 && ty<0)
         {
            ArrayResize(memory_ti,size+1); memory_ti[size]=OrderTicket();
            ArrayResize(memory_ty,size+1); memory_ty[size]=OrderType();
            ArrayResize(memory_sl,size+1); memory_sl[size]=attrStopLoss();
            ArrayResize(memory_tp,size+1); memory_tp[size]=attrTakeProfit();
            ArrayResize(memory_vl,size+1); memory_vl[size]=OrderLots();
            e_reason="new";
            e_detail="";
            break;
         }
         
         // Check for Lots, SL or TP modification
         else if (ty>=0 && i>-1) {
            if (memory_vl[i]!=OrderLots())
            {
               memory_vl[i]=OrderLots();
               e_reason="modify";
               e_detail="lots";
               break;
            }
            else {
               if (memory_sl[i]!=attrStopLoss())   {memory_sl[i]=attrStopLoss(); e_reason="modify"; e_detail="sl"; break;}
               if (memory_tp[i]!=attrTakeProfit()) {memory_tp[i]=attrTakeProfit(); e_reason="modify"; if (e_detail=="sl") {e_detail="sltp";} else {e_detail="tp";} break;}
            }
         }
      }
   }
   
   // Check for closed orders/trades
   bool missing=true;
   if (e_reason=="" && pending_opens==false && ArraySize(tickets_now)<ArraySize(memory_ti))
   {
      for(i=ArraySize(memory_ti)-1; i>=0; i--) { // for each ticket in the memory...
         for(j=0; j<=ArraySize(tickets_now); j++) { // check if trade exists now
            if (memory_ti[i]==tickets_now[j]) {missing=false; break;}
         }
         if (missing==true) {
            if (OrderSelect(memory_ti[i],SELECT_BY_TICKET))
            {
               // This can happen more than once
               ArrayStripKey(memory_ti,i);
               ArrayStripKey(memory_ty,i);
               ArrayStripKey(memory_sl,i);
               ArrayStripKey(memory_tp,i);
               ArrayStripKey(memory_vl,i);
               
               e_reason="closed";
               e_detail="";
               break;
            }
         }
         missing=true;
      }
   }
   // TRADES AND ORDERS
   ///////
   
   if (e_reason!="") {
      UpdateEventValues(e_reason,e_detail);
      EventTrade();
      OnTradeListener();
      if (USE_VIRTUAL_STOPS && e_reason=="closed") {
         ObjectDelete("#"+OrderTicket()+" sl");
         ObjectDelete("#"+OrderTicket()+" tp");
      }
      return;
   }
}
int OnTradeQueue(int queue=0)
{
   static int mem=0;
   mem=mem+queue;
   return(mem);
}
double PipValue(string symbol="")
{
   if (symbol=="") {symbol=GetSymbol();}
   return(CustomPoint(symbol)/MarketInfo(symbol,MODE_POINT));
   /*
   if (symbol=="") {symbol=GetSymbol();}
   int digits=MarketInfo(symbol,MODE_DIGITS);
   if ((digits==2 || digits==4)) {return(POINT_FORMAT/0.0001);}
   if ((digits==3 || digits==5)) {return(POINT_FORMAT/0.00001);}
   if ((digits==6))              {return(POINT_FORMAT/0.000001);}
   return(1);
   */
}
// Collect events, if any
void RegisterEvent(string command="")
{
   int ticket=OrderTicket();
	OnTradeListener();
   ticket=OrderSelect(ticket,SELECT_BY_TICKET);
   return;
}
void StringExplode(string delimiter, string explode, string &sReturn[])
{
   static int ilBegin; ilBegin = -1;
   static int ilEnd; ilEnd = 0;
   static int ilElement; ilElement = 0;
   
   static string sDelimiter; sDelimiter = delimiter;
   static string sExplode; sExplode = explode;
   
   while (ilEnd != -1)
   {
      ilEnd = StringFind(sExplode, sDelimiter, ilBegin+1);
      ArrayResize(sReturn,ilElement+1);
      sReturn[ilElement] = "";     
      if (ilEnd == -1){
         if (ilBegin+1 != StringLen(sExplode)){
            sReturn[ilElement] = StringSubstr(sExplode, ilBegin+1, StringLen(sExplode));
         }
      } else { 
         if (ilBegin+1 != ilEnd){
            sReturn[ilElement] = StringSubstr(sExplode, ilBegin+1, ilEnd-ilBegin-1);
         }
      }      
      ilBegin = StringFind(sExplode, sDelimiter,ilEnd);  
      ilElement++;    
   }
}
string StringTrim(string text)
{
   static string t; t = text;
   t = StringTrimRight(t);
   t = StringTrimLeft(t);
	return(t);
}
double TicksData(string symbol="", int type=0, int shift=0)
{
   
   //return(MarketInfo(symbol,type));
   static bool collecting_ticks=false;
   //static string feeded_symbols[];
   static string symbols[1];
   static int zero_sid[1];
   static double memoryASK[1][100];
   static double memoryBID[1][100];
   int sid; int size; int i; int id;
   double ask, bid, retval;
   bool exists=false;
   
   if (symbols[0]!=Symbol()) {symbols[0]=Symbol();}
   
   if (symbol=="") {symbol=Symbol();}
	
   if (type>0 && shift>0) {collecting_ticks=true;}
   if (collecting_ticks==false) {
      if (type>0 && shift==0) {
         // going to get ticks
      } else {return(0);}
   }
   
	if (type==0)
	{
      //StringExplode(",",symbol,feeded_symbols);
	   //for (s=0; s<ArraySize(feeded_symbols); s++)
	   //{
	      //symbol=feeded_symbols[s];
         //if (symbol=="") {symbol=Symbol();}
	      exists=false;
         size=ArraySize(symbols);
	      for (i=0; i<size; i++) {
	         if (symbols[i]==symbol) {exists=true; sid=i; break;}
	      }
         if (exists==false) {
            int newsize=ArraySize(symbols)+1;
            ArrayResize(symbols,newsize); symbols[newsize-1]=symbol;
            ArrayResize(zero_sid,newsize);
            ArrayResize(memoryASK,newsize);
            ArrayResize(memoryBID,newsize);
            sid=newsize;
         }
         if (sid>=0) {
            ask=MarketInfo(symbol,MODE_ASK);
            bid=MarketInfo(symbol,MODE_BID);
            if (bid==0 && MQLInfoInteger(MQL_TESTER)) {
               Print("Ticks data collector error: "+symbol+" cannot be backtested. Only the current symbol can be backtested. The EA will be terminated.");
               ExpertRemove();
            }
            if (symbol==Symbol() || ask!=memoryASK[sid][0] || bid!=memoryBID[sid][0])
            {
               memoryASK[sid][zero_sid[sid]]=ask;
               memoryBID[sid][zero_sid[sid]]=bid;
               zero_sid[sid]=zero_sid[sid]+1;
               if (zero_sid[sid]==100) {zero_sid[sid]=0;}
	         }
   	   }
      //}
   }
   else {
      if (shift<=0) {
         if (type==MODE_ASK) {
            return(MarketInfo(symbol, MODE_ASK));
         }
         else if (type==MODE_BID) {
            return(MarketInfo(symbol, MODE_BID)); 
         }
         else {
            double mid=((MarketInfo(symbol, MODE_ASK)+MarketInfo(symbol, MODE_BID))/2);
            return(mid);
         }
      }
      else {
         size=ArraySize(symbols);
         for (i=0; i<size; i++) {
            if (symbols[i]==symbol) {sid=i;}
         }
         if (shift<100) {
            id=zero_sid[sid]-shift-1; if(id<0) {id=id+100;}
            
            if (type==MODE_ASK) {
               retval=(memoryASK[sid][id]);
               if (retval==0) {retval=MarketInfo(symbol,MODE_ASK);}
            }
            else if (type==MODE_BID) {
               retval=(memoryBID[sid][id]);
               if (retval==0) {retval=MarketInfo(symbol,MODE_BID);}
            }
            //Print(shift+" "+id+" "+retval);
         }
      }
   }
   return(retval);
}
int TicksFromStart(bool upd=false)
{
   static int ticks=1;
   if (upd==true) {ticks++; if (ticks<0) ticks=0;}
   return(ticks);
}
datetime TimeAtStart(string cmd="server")
{
   static datetime local=0;
   static datetime server=0;
	
   if (cmd=="local") {return(local);}
   else if (cmd=="server") {return(server);}
   else if (cmd=="set") {
      local=TimeLocal();
      server=TimeCurrent();
   }
   return(0);
}
void UpdateEventValues(string e_reason="",string e_detail="")
{
   OnTradeQueue(1);
   e_Reason(true,e_reason);
   e_ReasonDetail(true,e_detail);
   e_attrClosePrice (true,attrClosePrice());
   e_attrComment    (true,attrComment());
   e_attrCommission (true,attrCommission());
   e_attrExpiration (true,attrExpiration());
   e_attrLots       (true,attrLots());
   e_attrMagicNumber(true,attrMagicNumber());
   e_attrOpenPrice  (true,attrOpenPrice());
   e_attrProfit     (true,attrProfit());
   e_attrStopLoss   (true,attrStopLoss());
   e_attrSymbol     (true,attrSymbol());
   e_attrTakeProfit (true,attrTakeProfit());
   e_attrTicket     (true,attrTicket());
   e_attrType       (true,attrType());
   // Not set, just execute without reason
   e_attrOpenTime();
   e_attrSwap();
}
double VirtualStopsDriver(string _command="", int _ti=-1, double _sl=0, double _tp=0, double _slp=0, double _tpp=0)
{
   if (!USE_VIRTUAL_STOPS) {return(0);} // Virtual stops are not enabled => stop here
   
   static int mem_to_ti[]; // tickets
   static int mem_to[];    // timeouts
   static int last_checked_ticket=0;
   
   static string command;  command=_command;
   static int ti;          ti=_ti;
   static double sl;       sl=_sl;
   static double tp;       tp=_tp;
   static double slp;      slp=_slp;
   static double tpp;      tpp=_tpp;
   
   static int i; i=0;
   static int ii; ii=-1;
   static int size; size=0;
   static int error; error=0;
   static int pos;
   static int total;
   static string name;
   static double ask, bid;
   static string print;
   
   // Listen trades/orders
   if (command=="" || command=="listen")
   {
      //-- delete lines of virtual stops of manually closed trades ------
      total = OrdersHistoryTotal();
      if (total>0)
      {
         static int prev_ticket; prev_ticket=0;
         for (pos=total-1; pos>=0; pos--)
         {
            if (OrderSelect(pos,SELECT_BY_POS,MODE_HISTORY))
            {
               if (OrderTicket()==last_checked_ticket) {break;}
               prev_ticket=OrderTicket();
               static bool clear; clear=true;
               
               name = "#"+OrderTicket()+" sl";
               if (ObjectFind(name)<0) {
                  error=GetLastError();
               }
               else {
                  clear=false;
                  ObjectDelete(name);
               }
               
               name = "#"+OrderTicket()+" tp";
               if (ObjectFind(name)<0) {
                  clear=true;
                  error=GetLastError();
               }
               else {
                  clear=false;
                  ObjectDelete(name);
               }
            }
         }
      
         if (prev_ticket==0) {prev_ticket=OrderTicket();}
         last_checked_ticket = prev_ticket;
      }
      
      //-- parse trades -------------------------------------------------
      total = OrdersTotal();
      for (pos=0; pos<total; pos++)
      {
         if (OrderSelect(pos,SELECT_BY_POS))
         {
            static int ticket;
            static string symbol;
            static double lots;
            static double cp;
            ticket   = OrderTicket();
            symbol   = OrderSymbol();
            lots     = OrderLots();
            cp       = OrderClosePrice();
            
            // check SL and TP
            static double sl_lvl;
            static double tp_lvl;
            
            name = "#"+ticket+" sl";
            sl_lvl = ObjectGet(name,OBJPROP_PRICE1);
            name = "#"+ticket+" tp";
            tp_lvl = ObjectGet(name,OBJPROP_PRICE1);
            
            // close trade/order
            if (OrderType()==OP_BUY)
            {
               bid = MarketInfo(symbol,MODE_BID);
               if ((sl_lvl>0 && bid<=sl_lvl) || (tp_lvl>0 && bid>=tp_lvl))
               {
                  if (VIRTUAL_STOPS_TIMEOUT>0 && (sl_lvl>0 && bid<=sl_lvl))
                  {
                     i=ArraySearch(mem_to_ti, ticket);
                     if (i<0)
                     { // start timeout
                        size = ArraySize(mem_to_ti);
                        ArrayResize(mem_to_ti, size+1);
                        ArrayResize(mem_to, size+1);
                        mem_to_ti[size]   = ticket;
                        mem_to[size]      = TimeLocal();
                        print = StringConcatenate("#",ticket," timeout of ",VIRTUAL_STOPS_TIMEOUT," seconds started");
                        Print(print);
                        return(0);
                     }
                     else {
                        if (TimeLocal()-mem_to[i] <= VIRTUAL_STOPS_TIMEOUT) {return(0);}
                     }
                  }
                  if (OrderClose(ticket, lots, cp, 0, clrNONE))
                  {
                     OnTradeListener(); // check this before deleting the lines
                     name = "#"+OrderTicket()+" sl";
                     ObjectDelete(name);
                     name = "#"+OrderTicket()+" tp";
                     ObjectDelete(name);
                  }
                  return(0);
               }
               else
               {
                  if (VIRTUAL_STOPS_TIMEOUT>0) {
                     i=ArraySearch(mem_to_ti,ticket);
                     if (i>=0) {
                        ArrayStripKey(mem_to_ti,i);
                        ArrayStripKey(mem_to,i);
                     }
                  }
               }
            }
            else if (OrderType()==OP_SELL)
            {
               ask = MarketInfo(symbol,MODE_ASK);
               if ((sl_lvl>0 && ask>=sl_lvl) || (tp_lvl>0 && ask<=tp_lvl))
               {
                  if (VIRTUAL_STOPS_TIMEOUT>0 && (sl_lvl>0 && ask>=sl_lvl))
                  {
                     i=ArraySearch(mem_to_ti, ticket);
                     if (i<0)
                     { // start timeout
                        size = ArraySize(mem_to_ti);
                        ArrayResize(mem_to_ti, size+1);
                        ArrayResize(mem_to, size+1);
                        mem_to_ti[size]   = ticket;
                        mem_to[size]      = TimeLocal();
                        print = StringConcatenate("#",ticket," timeout of ",VIRTUAL_STOPS_TIMEOUT," seconds started");
                        Print(print);
                        return(0);
                     }
                     else {
                        if (TimeLocal()-mem_to[i] <= VIRTUAL_STOPS_TIMEOUT) {return(0);}
                     }
                  }
                  if (OrderClose(ticket, lots, cp, 0, clrNONE))
                  {
                     OnTradeListener(); // check this before deleting the lines
                     name = "#"+OrderTicket()+" sl";
                     ObjectDelete(name);
                     name = "#"+OrderTicket()+" tp";
                     ObjectDelete(name);
                  }
                  return(0);
               }
               else
               {
                  if (VIRTUAL_STOPS_TIMEOUT>0)
                  {
                     i=ArraySearch(mem_to_ti,ticket);
                     if (i>=0) {
                        ArrayStripKey(mem_to_ti,i);
                        ArrayStripKey(mem_to,i);
                     }
                  }
               }
            }
         }
      }
   }
   // Set SL and TP
   else if ((command=="set" || command=="modify" || command=="clear" || command=="partial") && ti>-1)
   {
      static string settext;
      // update record (add/modify)
      name = "#"+ti+" sl";
      if (sl>0) {
         if (ObjectFind(name)==-1)
         {
            ObjectCreate(name,OBJ_HLINE,0,0,sl);
            ObjectSet(name,OBJPROP_WIDTH,1);
            ObjectSet(name,OBJPROP_COLOR,DeepPink);
            ObjectSet(name,OBJPROP_STYLE,STYLE_DOT);
            settext = name+" (virtual)";
            ObjectSetText(name, settext);
            error=GetLastError();
         }
         else {
            ObjectSet(name,OBJPROP_PRICE1,sl);
         }
      } else {ObjectDelete(name);}
      
      name="#"+ti+" tp";
      if (tp>0)
      {
         if (ObjectFind(name)==-1) {
            ObjectCreate(name,OBJ_HLINE,0,0,tp);
            ObjectSet(name,OBJPROP_WIDTH,1);
            ObjectSet(name,OBJPROP_COLOR,DodgerBlue);
            ObjectSet(name,OBJPROP_STYLE,STYLE_DOT);
            settext = name+" (virtual)";
            ObjectSetText(name, settext);
            error=GetLastError();
         }
         else {
            ObjectSet(name, OBJPROP_PRICE1, tp);
         }
      }
      else {
         ObjectDelete(name);
      }
      
      // print message
      if (command=="set" || command=="modify") {
         print = command+" #"+ti+": virtual sl "+DoubleToStr(sl,Digits)+" tp "+DoubleToStr(tp,Digits);
         Print(print);
      }
      return(1);
   }
   
   // Get SL or TP
   else if ((command=="get sl" || command=="get tp") && ti>0)
   {
      if (command=="get sl")
      {
         name = "#"+ti+" sl";
         if (ObjectFind(name) == -1) {error=GetLastError();return(0);} 
         return(ObjectGet(name, OBJPROP_PRICE1));
      }
      else if (command=="get tp")
      {
         name = "#"+ti+" tp";
         if (ObjectFind(name) == -1) {error=GetLastError();return(0);}
         return(ObjectGet(name, OBJPROP_PRICE1));
      }
      return(0);
   }
   
   return(1);
}
void WaitTradeContextIfBusy()
{
	if(IsTradeContextBusy()) {
      while(true)
      {
         Sleep(1);
         if(!IsTradeContextBusy()) {
            RefreshRates();
            break;
         }
      }
   }
   return;
}
int CustomDigits(string symbol="") {
	if (symbol=="") {symbol=GetSymbol();}
	double point=CustomPoint(symbol);
	if (point==0) {return(0);}
	int digits=0;
	while(true) {
		if (point>=1) {break;}
		point=point*10;
		digits++;
	}
	return(digits);
}
double CustomPoint(string symbol="") {
	static string symbols[];
	static double points[];
	static string last_symbol="-";
	static double last_point=0;
	static int last_i=0;
	static int size=0;

	if (symbol=="") {symbol=GetSymbol();}
	if (symbol==last_symbol) {return(last_point);}

	int i=last_i;
	int start_i=i;
	bool found=false;
	if (size>0) {
		while(true) {
			if (symbols[i]==symbol) {
				last_symbol=symbol;
				last_point=points[i];
				last_i=i;
				return(last_point);
				break;
			}
			i++;
			if (i>=size) {i=0;}
			if (i==start_i) {break;}
		}
	}

	//if (MarketInfo(symbol, MODE_DIGITS)<=0) {Print("Market "+symbol+" does not exists!"); return(0);} // commented because for indices digits = 0

	i=size;
	size=size+1;
	ArrayResize(symbols, size);
	ArrayResize(points, size);
	symbols[i]=symbol;
	points[i]=0;
	last_symbol=symbol;
	last_i=i;

	if (MarketInfo(symbol, MODE_POINT)==0.001) {points[i]=0.01;}
	if (MarketInfo(symbol, MODE_POINT)==0.00001) {points[i]=0.0001;}
	if (MarketInfo(symbol, MODE_POINT)==0.000001) {points[i]=0.0001;}
	if (points[i]==0) {points[i]=MarketInfo(symbol, MODE_POINT);}
	last_point=points[i];
	return(last_point);
}


//+------------------------------------------------------------------+
//| END                                                              |
//| Created with fxDreema EA Builder           https://fxdreema.com/ |
//+------------------------------------------------------------------+
/*<fxdreema:eNrtWktv4zYQ/iuGD0V72EJvWQr2sJtk2wJJ49bZQ08GLdEOa1kUSDpeY5H/3uFDL0eyU28W2RjJwYFnhp+G38zQ5FAoHsVfOXwMORaC5As+PEOx40qh7cTDgtF/cSKmOVrh4RmPHZCdZ5TjaYHzFOynaC4wm96OpbY5QmwLNSKIh/hLgZkoDRKa4gzlizVaKAMvHl7/deUptR0PUyTwNGEY/g3PSGx7jh34vu2ETf2KpmS+NXrH853QLfUrtCDJlAtknhgPrRJ6ltFkyeVg3FKF8XDBUHE3pYzgXCBBaF6OuaXFLf1IhaArJYLpoESQe/CRginJMTOTuCXJUlEEo+4JJ7MMTzMyY4htpwtG14Vhg2+5wBosqi2Vb312bjwUZAU0cwxPTbl6TDwMqpkVlORiytYZVvGD8JHYkoGUcQTf5ky778OUf7Us2wAIanwHIcgegM6OQaEetDssMGI90OkYOCoH7hn5oPlfQ0bdEybWKIPY0aKcYk5rShvaqaSDroXMAMswKSEwkLTAebLtAJE2O/opw1krEzpMUJru5hG+hyyp88iT0dGxVwBam2yTTFYJIzRViSrVYMrJap3JHJZjeBNazrKtna4QW2JhOLv8/PfnyYUaMarrDIqLsCplrXgIpKqYbUie0o3KB3D6a0NmK5llCl/L/rgwoa5MeBzJgBU38znHimnXVVzDMzI8F7Xciyxt3VsS8ZCkJXtXlBa/EyCXbc1DCLC15qrCZiqc4FVKOIK6SEuRTJICMViGYLkBe0qZrgM1Y5XZPEFZueTklK1QZvBNFeopPnKhyZZzmBmnixnP/2ZmoMYvcAazG+uF9UW4eexEkx33MDtuFzu2983sgNvndzhZ3jKUYn5O17l4EYI6/Why5B3myOviyPH95+LohqUwy5fnqOVHkyP/MEd+5/oTfXMe+br4cfo73ah9TPoiFHW50WQoOMxQ0FlpUXcW+Y7fwRB4ofK4TRE8ECvxVH2+IEs9njSJCg8TFXaWW9hDlGc9mahXsGKPDtMz6qy0oLvSfN86zTyKDhMVdf7w9/y0+aF/AnlUUWFbvfy0bB4T5FvdhRbYp7Ui1TTYT6Cqc3vtBz1UBa8/lx70xGr8vmNJKEUA0HkggXlurnrOEVL3Z3mM+kTZAKPkbqAjNKiYknjnLSbkuHEdMomsNy6ThOoOhi/bA+ZcXqt/K0WGHqmZbFczmlUD1SFeSsyXyT/XH2+udsZ8XG/5DZvgLONm1zKj4q7kUU7ygjA46JU9CUk93mAu3gn6jmawCxUmt6TtZEmaTkVaenmPNUlt8RVZkbJJYht2xojzy7xx5H3Qbm4mWAYP2Fah8yVXQB23m+OlwGkdaUHg7lp4uwK/Fpg1eSKQWOtWlHwQRIDmdD5vQnuqFYTqQ++jc1xfKjntVOoqmTqZwlI7MA2vAVXh/ymf8eLsQEqNfsSMkkGX+rJB0tBDEk0yUhSmMwdYOngA/oEx2KrSjDJjeIFxMSb5si9D3IMZYndkyDPF390Xf7cd/56jZZ0CnjEYCGUxSKTJ0+MP+nO6AmrKpfr9+7IVauTVM8u5QX2qZLg2HaZmvvhG1ww6/L9WnaJyQCD7oI3W0XX15Rny5AeMt7cv3l53vHeOyVW8XaeMd7viv2/c7dONu/X94q46CUFP3P123LuP/nWZA0Kiwn5HNwMiBhsEIa/s9m0c1CovY0Gbm1O9ej7TRIN9CR60J9q7Xa7nCon2M831gvaL3h2ZuT4pv5UjL52skbmJKuHk9UJRVbjUjBETBGXX9X2P3ZfF3lGr16P9zDNFO9wX7fBt+/Lk7Yv3Orcvo33xH71V+2lVe7Qv2tFbtZ9ote8013YSYKet9lbvr77edzqEvfG23yr+JCve+JHQPNftPAUQGT8Sq/IK4OYEZ+Wx4+Ly04fPV7clv3TNEvz4fAsqgdhCV1iza/qg4e2j4e1+eL+Cd46G9/vhnQrePRre7Yf3KnjvaPigHz6s
4P2j4cN++FEFHxwNP+qHjyr48Gj46BF861fN4I/+L/7OT2PPA+xql4W/CMx0tVnx14fyKoULlIu29B4xIu9EGlLwCTGMeHXQN4LGLU91+1KryvrHO129vhcUXHUVpG7wLUur5B2QumEc+Rp6Q1K5DIJJ4Opp32GyuNNGapQvX0QT+oZG3oKYy4/ZdnCLlngwZpTMRfWeJeYJI0XzXceLtigo35gs2YC//wBp4/FY
:fxdreema>*/