//+------------------------------------------------------------------------------+//
//)   ____  _  _  ____  ____  ____  ____  __  __    __      ___  _____  __  __   (//
//)  ( ___)( \/ )(  _ \(  _ \( ___)( ___)(  \/  )  /__\    / __)(  _  )(  \/  )  (//
//)   )__)  )  (  )(_) ))   / )__)  )__)  )    (  /(__)\  ( (__  )(_)(  )    (   (//
//)  (__)  (_/\_)(____/(_)\_)(____)(____)(_/\/\_)(__)(__)()\___)(_____)(_/\/\_)  (//
//)   http://fxdreema.com                              Copyright 2016, 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-5860"
#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  0 // "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 //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
// Formula Results
int CountersResetList[];

extern string inp51="(51) Sell now&nbsp;";
extern double inp51_VolumeRisk=1.0; // 
extern double inp51_dlStopLoss_Value=000; // 
extern double inp51_TakeProfitPips=50; // 
extern int MagicStart=5860; // 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; // Pass
bool block14=true; // Draw Button&nbsp;
bool block15=true; // Draw Button&nbsp;
bool block16=true; // Draw Button&nbsp;
bool block17=true; // Draw Button&nbsp;
bool block18=true; // Draw Button&nbsp;
bool block25=true; // Draw Text&nbsp;
bool block49=true; // Pass
bool block50=true; // Delete objects
bool block26=true; // (on trade) New trade opened
bool block27=true; // Draw Line&nbsp;
bool block28=true; // (on chart) Mouse click on object&nbsp;
bool block32=true; // Counter: Pass once
bool block34=true; // (on chart) Mouse click on object&nbsp;
bool block36=true; // Modify stops of trades&nbsp;
bool block37=true; // (on chart) Mouse click on object&nbsp;
bool block38=true; // close (partially)&nbsp;
bool block45=true; // (on chart) Mouse click on object&nbsp;
bool block46=true; // close (partially)&nbsp;
bool block47=true; // (on chart) Mouse click on object&nbsp;
bool block48=true; // Close trades&nbsp;
bool block51=true; // Sell now&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("");
	for (int i=ObjectsTotal(ChartID()); i>=0; i--)
	{
	   string name = ObjectName(ChartID(), i);
	   if (StringSubstr(name,0,8) == "fxd_cmnt") {ObjectDelete(ChartID(), name);}
	}
	ChartRedraw();

	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);
		}
	}
	block14();
	block15();
	block16();
	block17();
	block18();
	block25();

	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)
	TicksPerSecond(false, true); // Collect ticks per second
	if (USE_VIRTUAL_STOPS) {VirtualStopsDriver();}
	ExpirationDriver();
	OCODriver(); // Check and close OCO orders
	if (ENABLE_EVENT_TRADE) {OnTradeListener();}

	// Main beginning on the graph
	



	TicksFromStart(true);
	return;
}

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// This function is executed on trade events - open, close, modify //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
void EventTrade()
{
	block26();

	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;
		}
	}


}

//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//
// This function is executed when chart event happens //
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//
void OnChartEvent(const int id,	// Event ID
			const long& lparam,	// Parameter of type long event
			const double& dparam, // Parameter of type double event
			const string& sparam  // Parameter of type string events
)
{
	// Set ChartEvent things into memory functions
	ChartEventType(1,id);
	ChartEventParameterLong(1,lparam);
	ChartEventParameterDouble(1,dparam);
	ChartEventParameterString(1,sparam);

	block28();
	block34();
	block37();
	block45();
	block47();

}

//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");
	block49();
	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 (Pass) //
void block1(int _parent_=0)
{
	if (block1==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=1;

	/* Orange output */
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #14 (Draw Button&nbsp;) //
void block14(int _parent_=0)
{
	if (block14==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=14;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	bool ObjectPerBar=false; // This block can create 1 object per bar
	bool ObjectUpdate=true; // Redraw the current object
	string ObjName="RASELL"; // Object name/prefix (optional)
	int ObjX=30; // X-distance
	int ObjY=80; // Y-distance
	string ObjFont="Arial"; // Font
	int ObjFontSize=14; // Font size
	int ObjXsize=120; // Width
	int ObjYsize=25; // Height
	color ObjBgColor=clrCrimson; // Background color
	color ObjBorderColor=clrBlack; // Border color
	int ObjCorner=CORNER_LEFT_LOWER; // Corner
	bool ObjState=false; // State
	color ObjColor=clrOrange; // Color (text)
	bool ObjBack=false; // In the background
	bool ObjSelectable=false; // Selectable
	bool ObjSelected=false; // Selected
	bool ObjHidden=false; // Visibility
	int ObjZorder=0; // Z-order
	string ObjChartSubWindow=""; // Chart Sub-Window
	
	///////////////
	// Main code //
	///////////////
	
	long ObjChartID = 0;
	int subwindow_id = WindowFindVisible(ObjChartID, ObjChartSubWindow);
	
	if (subwindow_id >= 0)
	{
	   string name          = "";
	   string name_base     = "";
	   static int count     = 0;
	   static datetime time0= 0;
	   bool get_new_name    = false;
	   bool do_update       = true;
	   
	   if (ObjectPerBar==true) {
	      datetime time=iTime(Symbol(),0,1);
	      if (time0 < time) {
	         time0 = time;
	         get_new_name = true;
	      } else {
	         if (ObjectUpdate==false) {do_update = false;}
	      }
	   }
	   else {
	      if (ObjectUpdate==false) {get_new_name = true;}
	   }
	   
	   if (do_update)
	   {
	      if (ObjName!="") {name_base=ObjName;} else {name_base=StringConcatenate("fxd_button_","14","_");}
	      if (get_new_name == false) {
	         name=StringConcatenate(name_base,count);
	      } else {
	         while(true) {
	            count++;
	            name=StringConcatenate(name_base,count);
	            if (ObjectFind(ObjChartID,name)<0) {break;}
	         }
	      }
	      if (ObjName!="" && count==0) {name = ObjName;}
	   
	      if(ObjectFind(ObjChartID,name)<0 && !ObjectCreate(ObjChartID,name,OBJ_BUTTON,subwindow_id,0,0))
	      {
	         Print(__FUNCTION__,": failed to create button object! Error code = ",GetLastError());
	      }
	   
	      ObjectSetInteger(ObjChartID,name,OBJPROP_XDISTANCE,ObjX);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_YDISTANCE,ObjY);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_XSIZE,ObjXsize);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_YSIZE,ObjYsize);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BGCOLOR,ObjBgColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BORDER_COLOR,ObjBorderColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_CORNER,ObjCorner);
	      ObjectSetString(ObjChartID,name,OBJPROP_FONT,ObjFont);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_FONTSIZE,ObjFontSize);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_STATE,ObjState);
	      ObjectSetString(ObjChartID,name,OBJPROP_TEXT,(string)_text("Sell now!"));
	      
	      ObjectSetInteger(ObjChartID,name,OBJPROP_COLOR,ObjColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BACK,ObjBack);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_SELECTABLE,ObjSelectable);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_SELECTED,ObjSelected);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_HIDDEN,ObjHidden);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_ZORDER,ObjZorder);
	      
	      ChartRedraw();
	   }
	}
	block1(14);
}
string _text(string Text) {
	return(Text);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #15 (Draw Button&nbsp;) //
void block15(int _parent_=0)
{
	if (block15==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=15;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	bool ObjectPerBar=false; // This block can create 1 object per bar
	bool ObjectUpdate=true; // Redraw the current object
	string ObjName="RASLBE1"; // Object name/prefix (optional)
	int ObjX=40; // X-distance
	int ObjY=110; // Y-distance
	string ObjFont="Arial"; // Font
	int ObjFontSize=12; // Font size
	int ObjXsize=100; // Width
	int ObjYsize=25; // Height
	color ObjBgColor=clrCrimson; // Background color
	color ObjBorderColor=clrBlack; // Border color
	int ObjCorner=CORNER_LEFT_LOWER; // Corner
	bool ObjState=false; // State
	color ObjColor=clrOrange; // Color (text)
	bool ObjBack=false; // In the background
	bool ObjSelectable=false; // Selectable
	bool ObjSelected=false; // Selected
	bool ObjHidden=false; // Visibility
	int ObjZorder=0; // Z-order
	string ObjChartSubWindow=""; // Chart Sub-Window
	
	///////////////
	// Main code //
	///////////////
	
	long ObjChartID = 0;
	int subwindow_id = WindowFindVisible(ObjChartID, ObjChartSubWindow);
	
	if (subwindow_id >= 0)
	{
	   string name          = "";
	   string name_base     = "";
	   static int count     = 0;
	   static datetime time0= 0;
	   bool get_new_name    = false;
	   bool do_update       = true;
	   
	   if (ObjectPerBar==true) {
	      datetime time=iTime(Symbol(),0,1);
	      if (time0 < time) {
	         time0 = time;
	         get_new_name = true;
	      } else {
	         if (ObjectUpdate==false) {do_update = false;}
	      }
	   }
	   else {
	      if (ObjectUpdate==false) {get_new_name = true;}
	   }
	   
	   if (do_update)
	   {
	      if (ObjName!="") {name_base=ObjName;} else {name_base=StringConcatenate("fxd_button_","15","_");}
	      if (get_new_name == false) {
	         name=StringConcatenate(name_base,count);
	      } else {
	         while(true) {
	            count++;
	            name=StringConcatenate(name_base,count);
	            if (ObjectFind(ObjChartID,name)<0) {break;}
	         }
	      }
	      if (ObjName!="" && count==0) {name = ObjName;}
	   
	      if(ObjectFind(ObjChartID,name)<0 && !ObjectCreate(ObjChartID,name,OBJ_BUTTON,subwindow_id,0,0))
	      {
	         Print(__FUNCTION__,": failed to create button object! Error code = ",GetLastError());
	      }
	   
	      ObjectSetInteger(ObjChartID,name,OBJPROP_XDISTANCE,ObjX);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_YDISTANCE,ObjY);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_XSIZE,ObjXsize);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_YSIZE,ObjYsize);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BGCOLOR,ObjBgColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BORDER_COLOR,ObjBorderColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_CORNER,ObjCorner);
	      ObjectSetString(ObjChartID,name,OBJPROP_FONT,ObjFont);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_FONTSIZE,ObjFontSize);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_STATE,ObjState);
	      ObjectSetString(ObjChartID,name,OBJPROP_TEXT,(string)_text("SL to BE+1"));
	      
	      ObjectSetInteger(ObjChartID,name,OBJPROP_COLOR,ObjColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BACK,ObjBack);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_SELECTABLE,ObjSelectable);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_SELECTED,ObjSelected);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_HIDDEN,ObjHidden);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_ZORDER,ObjZorder);
	      
	      ChartRedraw();
	   }
	}
	block1(15);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #16 (Draw Button&nbsp;) //
void block16(int _parent_=0)
{
	if (block16==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=16;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	bool ObjectPerBar=false; // This block can create 1 object per bar
	bool ObjectUpdate=true; // Redraw the current object
	string ObjName="RAClose 1/4"; // Object name/prefix (optional)
	int ObjX=40; // X-distance
	int ObjY=140; // Y-distance
	string ObjFont="Arial"; // Font
	int ObjFontSize=12; // Font size
	int ObjXsize=100; // Width
	int ObjYsize=25; // Height
	color ObjBgColor=clrCrimson; // Background color
	color ObjBorderColor=clrBlack; // Border color
	int ObjCorner=CORNER_LEFT_LOWER; // Corner
	bool ObjState=false; // State
	color ObjColor=clrOrange; // Color (text)
	bool ObjBack=false; // In the background
	bool ObjSelectable=false; // Selectable
	bool ObjSelected=false; // Selected
	bool ObjHidden=false; // Visibility
	int ObjZorder=0; // Z-order
	string ObjChartSubWindow=""; // Chart Sub-Window
	
	///////////////
	// Main code //
	///////////////
	
	long ObjChartID = 0;
	int subwindow_id = WindowFindVisible(ObjChartID, ObjChartSubWindow);
	
	if (subwindow_id >= 0)
	{
	   string name          = "";
	   string name_base     = "";
	   static int count     = 0;
	   static datetime time0= 0;
	   bool get_new_name    = false;
	   bool do_update       = true;
	   
	   if (ObjectPerBar==true) {
	      datetime time=iTime(Symbol(),0,1);
	      if (time0 < time) {
	         time0 = time;
	         get_new_name = true;
	      } else {
	         if (ObjectUpdate==false) {do_update = false;}
	      }
	   }
	   else {
	      if (ObjectUpdate==false) {get_new_name = true;}
	   }
	   
	   if (do_update)
	   {
	      if (ObjName!="") {name_base=ObjName;} else {name_base=StringConcatenate("fxd_button_","16","_");}
	      if (get_new_name == false) {
	         name=StringConcatenate(name_base,count);
	      } else {
	         while(true) {
	            count++;
	            name=StringConcatenate(name_base,count);
	            if (ObjectFind(ObjChartID,name)<0) {break;}
	         }
	      }
	      if (ObjName!="" && count==0) {name = ObjName;}
	   
	      if(ObjectFind(ObjChartID,name)<0 && !ObjectCreate(ObjChartID,name,OBJ_BUTTON,subwindow_id,0,0))
	      {
	         Print(__FUNCTION__,": failed to create button object! Error code = ",GetLastError());
	      }
	   
	      ObjectSetInteger(ObjChartID,name,OBJPROP_XDISTANCE,ObjX);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_YDISTANCE,ObjY);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_XSIZE,ObjXsize);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_YSIZE,ObjYsize);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BGCOLOR,ObjBgColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BORDER_COLOR,ObjBorderColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_CORNER,ObjCorner);
	      ObjectSetString(ObjChartID,name,OBJPROP_FONT,ObjFont);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_FONTSIZE,ObjFontSize);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_STATE,ObjState);
	      ObjectSetString(ObjChartID,name,OBJPROP_TEXT,(string)_text("Close 1/4"));
	      
	      ObjectSetInteger(ObjChartID,name,OBJPROP_COLOR,ObjColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BACK,ObjBack);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_SELECTABLE,ObjSelectable);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_SELECTED,ObjSelected);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_HIDDEN,ObjHidden);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_ZORDER,ObjZorder);
	      
	      ChartRedraw();
	   }
	}
	block1(16);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #17 (Draw Button&nbsp;) //
void block17(int _parent_=0)
{
	if (block17==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=17;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	bool ObjectPerBar=false; // This block can create 1 object per bar
	bool ObjectUpdate=true; // Redraw the current object
	string ObjName="RAClose 1/2"; // Object name/prefix (optional)
	int ObjX=40; // X-distance
	int ObjY=170; // Y-distance
	string ObjFont="Arial"; // Font
	int ObjFontSize=12; // Font size
	int ObjXsize=100; // Width
	int ObjYsize=25; // Height
	color ObjBgColor=clrCrimson; // Background color
	color ObjBorderColor=clrBlack; // Border color
	int ObjCorner=CORNER_LEFT_LOWER; // Corner
	bool ObjState=false; // State
	color ObjColor=clrOrange; // Color (text)
	bool ObjBack=false; // In the background
	bool ObjSelectable=false; // Selectable
	bool ObjSelected=false; // Selected
	bool ObjHidden=false; // Visibility
	int ObjZorder=0; // Z-order
	string ObjChartSubWindow=""; // Chart Sub-Window
	
	///////////////
	// Main code //
	///////////////
	
	long ObjChartID = 0;
	int subwindow_id = WindowFindVisible(ObjChartID, ObjChartSubWindow);
	
	if (subwindow_id >= 0)
	{
	   string name          = "";
	   string name_base     = "";
	   static int count     = 0;
	   static datetime time0= 0;
	   bool get_new_name    = false;
	   bool do_update       = true;
	   
	   if (ObjectPerBar==true) {
	      datetime time=iTime(Symbol(),0,1);
	      if (time0 < time) {
	         time0 = time;
	         get_new_name = true;
	      } else {
	         if (ObjectUpdate==false) {do_update = false;}
	      }
	   }
	   else {
	      if (ObjectUpdate==false) {get_new_name = true;}
	   }
	   
	   if (do_update)
	   {
	      if (ObjName!="") {name_base=ObjName;} else {name_base=StringConcatenate("fxd_button_","17","_");}
	      if (get_new_name == false) {
	         name=StringConcatenate(name_base,count);
	      } else {
	         while(true) {
	            count++;
	            name=StringConcatenate(name_base,count);
	            if (ObjectFind(ObjChartID,name)<0) {break;}
	         }
	      }
	      if (ObjName!="" && count==0) {name = ObjName;}
	   
	      if(ObjectFind(ObjChartID,name)<0 && !ObjectCreate(ObjChartID,name,OBJ_BUTTON,subwindow_id,0,0))
	      {
	         Print(__FUNCTION__,": failed to create button object! Error code = ",GetLastError());
	      }
	   
	      ObjectSetInteger(ObjChartID,name,OBJPROP_XDISTANCE,ObjX);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_YDISTANCE,ObjY);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_XSIZE,ObjXsize);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_YSIZE,ObjYsize);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BGCOLOR,ObjBgColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BORDER_COLOR,ObjBorderColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_CORNER,ObjCorner);
	      ObjectSetString(ObjChartID,name,OBJPROP_FONT,ObjFont);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_FONTSIZE,ObjFontSize);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_STATE,ObjState);
	      ObjectSetString(ObjChartID,name,OBJPROP_TEXT,(string)_text("Close 1/2"));
	      
	      ObjectSetInteger(ObjChartID,name,OBJPROP_COLOR,ObjColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BACK,ObjBack);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_SELECTABLE,ObjSelectable);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_SELECTED,ObjSelected);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_HIDDEN,ObjHidden);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_ZORDER,ObjZorder);
	      
	      ChartRedraw();
	   }
	}
	block1(17);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #18 (Draw Button&nbsp;) //
void block18(int _parent_=0)
{
	if (block18==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=18;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	bool ObjectPerBar=false; // This block can create 1 object per bar
	bool ObjectUpdate=true; // Redraw the current object
	string ObjName="RAClose All"; // Object name/prefix (optional)
	int ObjX=30; // X-distance
	int ObjY=200; // Y-distance
	string ObjFont="Arial"; // Font
	int ObjFontSize=14; // Font size
	int ObjXsize=120; // Width
	int ObjYsize=25; // Height
	color ObjBgColor=clrCrimson; // Background color
	color ObjBorderColor=clrBlack; // Border color
	int ObjCorner=CORNER_LEFT_LOWER; // Corner
	bool ObjState=false; // State
	color ObjColor=clrOrange; // Color (text)
	bool ObjBack=false; // In the background
	bool ObjSelectable=false; // Selectable
	bool ObjSelected=false; // Selected
	bool ObjHidden=false; // Visibility
	int ObjZorder=0; // Z-order
	string ObjChartSubWindow=""; // Chart Sub-Window
	
	///////////////
	// Main code //
	///////////////
	
	long ObjChartID = 0;
	int subwindow_id = WindowFindVisible(ObjChartID, ObjChartSubWindow);
	
	if (subwindow_id >= 0)
	{
	   string name          = "";
	   string name_base     = "";
	   static int count     = 0;
	   static datetime time0= 0;
	   bool get_new_name    = false;
	   bool do_update       = true;
	   
	   if (ObjectPerBar==true) {
	      datetime time=iTime(Symbol(),0,1);
	      if (time0 < time) {
	         time0 = time;
	         get_new_name = true;
	      } else {
	         if (ObjectUpdate==false) {do_update = false;}
	      }
	   }
	   else {
	      if (ObjectUpdate==false) {get_new_name = true;}
	   }
	   
	   if (do_update)
	   {
	      if (ObjName!="") {name_base=ObjName;} else {name_base=StringConcatenate("fxd_button_","18","_");}
	      if (get_new_name == false) {
	         name=StringConcatenate(name_base,count);
	      } else {
	         while(true) {
	            count++;
	            name=StringConcatenate(name_base,count);
	            if (ObjectFind(ObjChartID,name)<0) {break;}
	         }
	      }
	      if (ObjName!="" && count==0) {name = ObjName;}
	   
	      if(ObjectFind(ObjChartID,name)<0 && !ObjectCreate(ObjChartID,name,OBJ_BUTTON,subwindow_id,0,0))
	      {
	         Print(__FUNCTION__,": failed to create button object! Error code = ",GetLastError());
	      }
	   
	      ObjectSetInteger(ObjChartID,name,OBJPROP_XDISTANCE,ObjX);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_YDISTANCE,ObjY);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_XSIZE,ObjXsize);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_YSIZE,ObjYsize);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BGCOLOR,ObjBgColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BORDER_COLOR,ObjBorderColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_CORNER,ObjCorner);
	      ObjectSetString(ObjChartID,name,OBJPROP_FONT,ObjFont);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_FONTSIZE,ObjFontSize);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_STATE,ObjState);
	      ObjectSetString(ObjChartID,name,OBJPROP_TEXT,(string)_text("Close All"));
	      
	      ObjectSetInteger(ObjChartID,name,OBJPROP_COLOR,ObjColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BACK,ObjBack);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_SELECTABLE,ObjSelectable);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_SELECTED,ObjSelected);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_HIDDEN,ObjHidden);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_ZORDER,ObjZorder);
	      
	      ChartRedraw();
	   }
	}
	block1(18);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #25 (Draw Text&nbsp;) //
void block25(int _parent_=0)
{
	if (block25==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=25;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	bool ObjectPerBar=false; // This block can create 1 object per bar
	bool ObjectUpdate=true; // Redraw the current object
	string ObjName="RAcreated"; // Object name/prefix (optional)
	int ObjectType=OBJ_LABEL; // Text placement
	int ObjX=19; // X coordinate
	int ObjY=200; // Y coordinate
	string ObjFont="Arial"; // Font
	int ObjFontSize=7; // Font size
	double ObjAngle=0; // Angle
	double ObjCorner=CORNER_LEFT_LOWER; // Corner
	int ObjAnchor=ANCHOR_LEFT_LOWER; // Anchor type
	color ObjColor=clrBlue; // Color
	bool ObjBack=false; // In the background
	bool ObjSelectable=false; // Selectable
	bool ObjSelected=false; // Selected
	bool ObjHidden=false; // Visibility
	int ObjZorder=0; // Z-order
	string ObjChartSubWindow=""; // Chart Sub-Window
	
	///////////////
	// Main code //
	///////////////
	
	long ObjChartID = 0;
	int subwindow_id = WindowFindVisible(ObjChartID, ObjChartSubWindow);
	
	if (subwindow_id >= 0)
	{
	   double p1=0, p2=0;
	   datetime t1=0, t2=0;
	   string name          = "";
	   string name_base     = "";
	   static int count     = 0;
	   static datetime time0= 0;
	   bool get_new_name    = false;
	   bool do_update       = true;
	   
	   if (ObjectPerBar==true) {
	      datetime time=iTime(Symbol(),0,1);
	      if (time0 < time) {
	         time0 = time;
	         get_new_name = true;
	      } else {
	         if (ObjectUpdate==false) {do_update = false;}
	      }
	   }
	   else {
	      if (ObjectUpdate==false) {get_new_name = true;}
	   }
	   
	   if (do_update)
	   {
	      if (ObjName!="") {name_base=ObjName;} else {name_base=StringConcatenate("fxd_text_","25","_");}
	      if (get_new_name == false) {
	         name=StringConcatenate(name_base,count);
	      } else {
	         while(true) {
	            count++;
	            name=StringConcatenate(name_base,count);
	            if (ObjectFind(ObjChartID,name)<0) {break;}
	         }
	      }
	      if (ObjName!="" && count==0) {name = ObjName;}
	      
	      if(ObjectFind(ObjChartID,name)<0 && !ObjectCreate(ObjChartID,name,ObjectType,subwindow_id,t1,p1,t2,p2))
	      {
	         Print(__FUNCTION__,": failed to create text object! Error code = ",GetLastError());
	      }
	      
	      if (ObjectType==OBJ_TEXT) {
	         ObjectSetInteger(ObjChartID,name,OBJPROP_TIME,0,_time(3, 0, "00:00", 0, "", 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false));
	         ObjectSetDouble(ObjChartID,name,OBJPROP_PRICE,0,_candles("iClose", "id", 0, "00:00", CurrentSymbol(), CurrentTimeframe()));
	      } else {
	         ObjectSetInteger(ObjChartID,name,OBJPROP_XDISTANCE,ObjX);
	         ObjectSetInteger(ObjChartID,name,OBJPROP_YDISTANCE,ObjY);
	      }
	      ObjectSetString(ObjChartID,name,OBJPROP_TEXT,(string)_text("Created by theras2000 at FFforum"));
	      ObjectSetString(ObjChartID,name,OBJPROP_FONT,ObjFont);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_FONTSIZE,ObjFontSize);
	      ObjectSetDouble(ObjChartID,name,OBJPROP_ANGLE,ObjAngle);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_CORNER,ObjCorner);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_ANCHOR,ObjAnchor);
	      
	      //ObjectSetInteger(ObjChartID,name,OBJPROP_STYLE,ObjStyle);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_COLOR,ObjColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BACK,ObjBack);
	      //ObjectSetInteger(ObjChartID,name,OBJPROP_WIDTH,ObjWidth);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_SELECTABLE,ObjSelectable);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_SELECTED,ObjSelected);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_HIDDEN,ObjHidden);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_ZORDER,ObjZorder);
	      
	      ChartRedraw();
	   }
	}
	block1(25);
}
datetime _time(int ModeTime, int TimeSource, string TimeStamp, int TimeCandleID, string TimeMarket, int TimeCandleTimeframe, int TimeComponentYear, int TimeComponentMonth, int TimeComponentDay, int TimeComponentHour, int TimeComponentMinute, int TimeComponentSecond, int ModeTimeShift, int TimeShiftYears, int TimeShiftMonths, int TimeShiftWeeks, int TimeShiftDays, int TimeShiftHours, int TimeShiftMinutes, int TimeShiftSeconds, bool TimeSkipWeekdays) {
	static datetime retval=0, retval0=0;
	static int ModeTime0=0;
	static int smodeshift=0;
	
	if(ModeTime==0) {
	   if (TimeSource==1) {retval=TimeLocal();} else {retval=TimeCurrent();}
	}
	else if(ModeTime==1) {
	      retval=StringToTime(TimeStamp);
	      retval0=retval;
	}
	else if(ModeTime==2) {
	   retval = TimeFromComponents(TimeSource == 1, TimeComponentYear, TimeComponentMonth, TimeComponentDay, TimeComponentHour, TimeComponentMinute, TimeComponentSecond);
	}
	else if(ModeTime==3) {
	   if (TimeMarket=="") {TimeMarket=Symbol();}
	   retval=iTime(TimeMarket,TimeCandleTimeframe,TimeCandleID);
	}
	
	if (ModeTimeShift>0) {
	   int sh=1;
	   if (ModeTimeShift==1) {sh=-1;}
	   
	   static int years0=0,months0=0;
	   
	   if (
	      ModeTimeShift!=smodeshift
	      || TimeShiftYears!=years0 || TimeShiftMonths!=months0
	   )
	   {
	      years0=TimeShiftYears; months0=TimeShiftMonths;
	      
	      if (TimeShiftYears>0 || TimeShiftMonths>0) {
	         int year=0,month=0,week=0,day=0,hour=0,minute=0,second=0;
	         if (ModeTime==3) {
	            year=TimeComponentYear; month=TimeComponentYear;    day=TimeComponentDay;
	            hour=TimeComponentHour; minute=TimeComponentMinute; second=TimeComponentSecond;
	         }
	         else {
	            year=TimeYear(retval); month=TimeMonth(retval);   day=TimeDay(retval);
	            hour=TimeHour(retval); minute=TimeMinute(retval); second=TimeSeconds(retval);
	         }
	         
	         year  =year+TimeShiftYears*sh;
	         month =month+TimeShiftMonths*sh;
	         if (month<0) {month=12-month;}
	         else if (month>12) {month=month-12;}
	         retval=StrToTime(year+"."+month+"."+day+" "+hour+":"+minute+":"+second);
	      }
	   }
	
	   retval=retval+TimeShiftWeeks*604800*sh+TimeShiftDays*86400*sh+TimeShiftHours*3600*sh+TimeShiftMinutes*60*sh+TimeShiftSeconds*sh;
	      
	   if (TimeSkipWeekdays==true) {
	      int weekday=TimeDayOfWeek(retval);
	      
	      if (sh>0) { // forward
	         if (weekday==0) {retval=retval+86400;}
	         else if (weekday==6) {retval=retval+172800;}
	      }
	      else if (sh<0) { // back
	         if (weekday==0) {retval=retval-172800;}
	         else if (weekday==6) {retval=retval-86400;}
	      }
	   }
	}
	smodeshift=ModeTimeShift;
	ModeTime0=ModeTime;
	
	return(retval);
}
double _candles(string iOHLC, string ModeCandleFindBy, int CandleID, string TimeStamp, string SYMBOL, int TIMEFRAME) {
	double retval=0;
	double cOpen=0;
	double cHigh=0;
	double cLow=0;
	double cClose=0;
	
	if (ModeCandleFindBy == "time")
	{
	   CandleID = iCandleID(SYMBOL, TIMEFRAME, StrToTime(TimeStamp));
	}
	
	CandleID=CandleID+IndicatorMoreShift();
	
	if (iOHLC=="iOpen")        {retval=iOpen(SYMBOL, TIMEFRAME, CandleID);}
	else if (iOHLC=="iHigh")   {retval=iHigh(SYMBOL, TIMEFRAME, CandleID);}
	else if (iOHLC=="iLow")    {retval=iLow(SYMBOL, TIMEFRAME, CandleID);}
	else if (iOHLC=="iClose")  {retval=iClose(SYMBOL, TIMEFRAME, CandleID);}
	else if (iOHLC=="iVolume") {retval=iVolume(SYMBOL, TIMEFRAME, CandleID);}
	else if (iOHLC=="iTime")   {retval=iTime(SYMBOL, TIMEFRAME, CandleID);}
	else
	{
	   if (iOHLC=="iMedian") {
	      cLow=iLow(SYMBOL,TIMEFRAME,CandleID);
	      cHigh=iHigh(SYMBOL,TIMEFRAME,CandleID);
	   	retval=((cLow+cHigh)/2);
	   }
	   else if (iOHLC=="iTypical") {
	   	cLow=iLow(SYMBOL,TIMEFRAME,CandleID);
	   	cHigh=iHigh(SYMBOL,TIMEFRAME,CandleID);
	   	cClose=iClose(SYMBOL,TIMEFRAME,CandleID);
	   	retval=((cLow+cHigh+cClose)/3);
	   }
	   else if (iOHLC=="iAverage") {
	   	cLow=iLow(SYMBOL,TIMEFRAME,CandleID);
	   	cHigh=iHigh(SYMBOL,TIMEFRAME,CandleID);
	   	cClose=iClose(SYMBOL,TIMEFRAME,CandleID);
	   	retval=((cLow+cHigh+cClose+cClose)/4);
	   }
	   else if (iOHLC=="iTotal") {
	   	cHigh=iHigh(SYMBOL,TIMEFRAME,CandleID);
	   	cLow=iLow(SYMBOL,TIMEFRAME,CandleID);
	   	retval=toPips(MathAbs(cHigh-cLow),SYMBOL);
	   }
	   else if (iOHLC=="iBody") {
	   	cOpen=iOpen(SYMBOL,TIMEFRAME,CandleID);
	   	cClose=iClose(SYMBOL,TIMEFRAME,CandleID);
	   	retval=toPips(MathAbs(cClose-cOpen),SYMBOL);
	   }
	   else if (iOHLC=="iUpperWick") {
	   	cHigh=iHigh(SYMBOL,TIMEFRAME,CandleID);
	   	cOpen=iOpen(SYMBOL,TIMEFRAME,CandleID);
	   	cClose=iClose(SYMBOL,TIMEFRAME,CandleID);
	   	cLow=iLow(SYMBOL,TIMEFRAME,CandleID);
	   	retval=0;
	   	if (cClose>cOpen) {
	   	   retval=toPips(MathAbs(cHigh-cClose),SYMBOL);
	   	} else {
	   	   retval=toPips(MathAbs(cHigh-cOpen),SYMBOL);
	   	}
	   }
	   else if (iOHLC=="iBottomWick") {
	   	cHigh=iHigh(SYMBOL,TIMEFRAME,CandleID);
	   	cOpen=iOpen(SYMBOL,TIMEFRAME,CandleID);
	   	cClose=iClose(SYMBOL,TIMEFRAME,CandleID);
	   	cLow=iLow(SYMBOL,TIMEFRAME,CandleID);
	   	retval=0;
	   	if (cClose>cOpen) {
	   	   retval=toPips(MathAbs(cOpen-cLow),SYMBOL);
	   	} else {
	   	   retval=toPips(MathAbs(cClose-cLow),SYMBOL);
	   	}
	   }
	   else if (iOHLC=="iBullTotal") {
	   	cOpen=iOpen(SYMBOL,TIMEFRAME,CandleID);
	   	cClose=iClose(SYMBOL,TIMEFRAME,CandleID);
	   	cHigh=iHigh(SYMBOL,TIMEFRAME,CandleID);
	   	cLow=iLow(SYMBOL,TIMEFRAME,CandleID);
	   	retval=toPips((cHigh-cLow),SYMBOL);
	   	if (cClose<cOpen) {return(EMPTY_VALUE);}
	   }
	   else if (iOHLC=="iBullBody") {
	   	cOpen=iOpen(SYMBOL,TIMEFRAME,CandleID);
	   	cClose=iClose(SYMBOL,TIMEFRAME,CandleID);
	   	retval=toPips((cClose-cOpen),SYMBOL);
	   	if (cClose<cOpen) {return(EMPTY_VALUE);}
	   }
	   else if (iOHLC=="iBullUpperWick") {
	   	cHigh=iHigh(SYMBOL,TIMEFRAME,CandleID);
	   	cOpen=iOpen(SYMBOL,TIMEFRAME,CandleID);
	   	cClose=iClose(SYMBOL,TIMEFRAME,CandleID);
	   	retval=toPips((cHigh-cClose),SYMBOL);
	   	if (cClose<cOpen) {return(EMPTY_VALUE);}
	   }
	   else if (iOHLC=="iBullBottomWick") {
	   	cLow=iLow(SYMBOL,TIMEFRAME,CandleID);
	   	cOpen=iOpen(SYMBOL,TIMEFRAME,CandleID);
	   	cClose=iClose(SYMBOL,TIMEFRAME,CandleID);
	   	retval=toPips((cOpen-cLow),SYMBOL);
	   	if (cClose<cOpen) {return(EMPTY_VALUE);}
	   }
	   else if (iOHLC=="iBearTotal") {
	   	cOpen=iOpen(SYMBOL,TIMEFRAME,CandleID);
	   	cClose=iClose(SYMBOL,TIMEFRAME,CandleID);
	   	cHigh=iHigh(SYMBOL,TIMEFRAME,CandleID);
	   	cLow=iLow(SYMBOL,TIMEFRAME,CandleID);
	   	retval=toPips((cHigh-cLow),SYMBOL);
	   	if (cOpen<cClose) {return(EMPTY_VALUE);}
	   }
	   else if (iOHLC=="iBearBody") {
	   	cOpen=iOpen(SYMBOL,TIMEFRAME,CandleID);
	   	cClose=iClose(SYMBOL,TIMEFRAME,CandleID);
	   	retval=toPips((cOpen-cClose),SYMBOL);
	   	if (cOpen<cClose) {return(EMPTY_VALUE);}
	   }
	   else if (iOHLC=="iBearUpperWick") {
	   	cHigh=iHigh(SYMBOL,TIMEFRAME,CandleID);
	   	cOpen=iOpen(SYMBOL,TIMEFRAME,CandleID);
	   	cClose=iClose(SYMBOL,TIMEFRAME,CandleID);
	   	retval=toPips((cHigh-cOpen),SYMBOL);
	   	if (cOpen<cClose) {return(EMPTY_VALUE);}
	   }
	   else if (iOHLC=="iBearBottomWick") {
	   	cLow=iLow(SYMBOL,TIMEFRAME,CandleID);
	   	cOpen=iOpen(SYMBOL,TIMEFRAME,CandleID);
	   	cClose=iClose(SYMBOL,TIMEFRAME,CandleID);
	   	retval=toPips((cClose-cLow),SYMBOL);
	   	if (cOpen<cClose) {return(EMPTY_VALUE);}
	   }
	}
	return(retval);
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #49 (Pass) //
void block49(int _parent_=0)
{
	if (block49==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=49;

	block50(49);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #50 (Delete objects) //
void block50(int _parent_=0)
{
	if (block50==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=50;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string NameStartsWith="RA"; // Name starts with
	string NameContains=""; // Name contains
	color ObjColor=EMPTY_VALUE; // Color
	string SortMode="z-a"; // Sort objects
	int MaxObjects=0; // Max objects to clear
	int SkipObjects=0; // Skip "n" objects
	
	///////////////
	// Main code //
	///////////////
	
	int index=0;
	int total=ObjectsTotal();
	int deleted_count=0;
	int skipped_count=0;
	string name="";
	int length=0;
	bool deleted=false;
	if (SortMode=="a-z")
	{
	   for (index=0; index<total; index++) {
	      name=ObjectName(index);
	      if (name!="") {
	         if (MaxObjects>0 && deleted_count>=MaxObjects) {break;}
	         deleted=false;
	         if (ObjColor!=EMPTY_VALUE && ObjectGet(name, OBJPROP_COLOR) != ObjColor) {continue;}
	         if (NameStartsWith=="" && NameContains=="") {
	            if (SkipObjects>0 && skipped_count<SkipObjects) {skipped_count++; continue;}
	            if (ObjectDelete(name)) {deleted_count++;}
	         }
	         else {
	            if (NameStartsWith!="") {
	               length=StringLen(NameStartsWith);
	               if (StringSubstr(name,0,length)==NameStartsWith) {
	                  if (SkipObjects>0 && skipped_count<SkipObjects) {skipped_count++; continue;}
	                  if (ObjectDelete(name)) {deleted_count++;}
	               }
	            }
	            if (deleted==false && NameContains!="") {
	               if (StringFind(name,NameContains,0)>-1) {
	                  if (SkipObjects>0 && skipped_count<SkipObjects) {skipped_count++; continue;}
	                  if (ObjectDelete(name)) {deleted_count++;}
	               }
	            }
	         }
	      }
	   }
	}
	else if (SortMode=="z-a")
	{
	   for (index=total-1; index>=0; index--) {
	      name=ObjectName(index);
	      if (name!="") {
	         if (MaxObjects>0 && deleted_count>=MaxObjects) {break;}
	         deleted=false;
	         if (ObjColor!=EMPTY_VALUE && ObjectGet(name, OBJPROP_COLOR) != ObjColor) {continue;}
	         if (NameStartsWith=="" && NameContains=="") {
	            if (SkipObjects>0 && skipped_count<SkipObjects) {skipped_count++; continue;}
	            if (ObjectDelete(name)) {deleted_count++;}
	         }
	         else {
	            if (NameStartsWith!="") {
	               length=StringLen(NameStartsWith);
	               if (StringSubstr(name,0,length)==NameStartsWith) {
	                  if (SkipObjects>0 && skipped_count<SkipObjects) {skipped_count++; continue;}
	                  if (ObjectDelete(name)) {deleted_count++;}
	               }
	            }
	            if (deleted==false && NameContains!="") {
	               if (StringFind(name,NameContains,0)>-1) {
	                  if (SkipObjects>0 && skipped_count<SkipObjects) {skipped_count++; continue;}
	                   
	                  if (ObjectDelete(name)) {deleted_count++;}
	               }
	            }
	         }
	      }
	   }
	}
	
	/* Orange output */
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #26 ((on trade) New trade opened) //
void block26(int _parent_=0)
{
	if (block26==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=26;

	//////////////////////
	// 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
	color ArrowColor=DeepPink; // Arrow color
	
	///////////////
	// Main code //
	///////////////
	
	if (
	      e_Reason()=="new"
	      &&
	      (FilterEventTrade(GroupMode,Group,MarketMode,Market,BuysOrSells))
	   )
	   {block27(26);} else {/* Yellow output */}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #27 (Draw Line&nbsp;) //
void block27(int _parent_=0)
{
	if (block27==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=27;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	bool ObjectPerBar=false; // This block can create 1 object per bar
	bool ObjectUpdate=true; // Redraw the current object
	string ObjName="RATP1"; // Object name/prefix (optional)
	int ObjectType=OBJ_HLINE; // Object type
	double ObjAngle=45; // Angle
	bool ObjRay=true; // Ray
	bool ObjRayLeft=false; // Ray left
	bool ObjRayRight=false; // Ray right
	color ObjColor=clrLimeGreen; // Color
	ENUM_LINE_STYLE ObjStyle=STYLE_DASHDOTDOT; // Line style
	int ObjWidth=0; // Width
	bool ObjBack=false; // In the background
	bool ObjSelectable=true; // Selectable
	bool ObjSelected=false; // Selected
	bool ObjHidden=false; // Visibility
	int ObjZorder=0; // Z-order
	string ObjChartSubWindow=""; // Chart Sub-Window
	
	///////////////
	// Main code //
	///////////////
	
	long ObjChartID = 0;
	int subwindow_id = WindowFindVisible(ObjChartID, ObjChartSubWindow);
	
	if (subwindow_id >= 0)
	{
	   double p1=0, p2=0;
	   datetime t1=0, t2=0;
	   string name          = "";
	   string name_base     = "";
	   static int count     = 0;
	   static datetime time0= 0;
	   bool get_new_name    = false;
	   bool do_update       = true;
	   
	   if (ObjectPerBar==true) {
	      datetime time=iTime(Symbol(),0,1);
	      if (time0 < time) {
	         time0 = time;
	         get_new_name = true;
	      } else {
	         if (ObjectUpdate==false) {do_update = false;}
	      }
	   }
	   else {
	      if (ObjectUpdate==false) {get_new_name = true;}
	   }
	   
	   if (do_update)
	   {
	      if (ObjName!="") {name_base=ObjName;} else {name_base=StringConcatenate("fxd_line_","27","_");}
	      if (get_new_name == false) {
	         name=StringConcatenate(name_base,count);
	      } else {
	         while(true) {
	            count++;
	            name=StringConcatenate(name_base,count);
	            if (ObjectFind(ObjChartID,name)<0) {break;}
	         }
	      }
	      if (ObjName!="" && count==0) {name = ObjName;}
	   
	      if(ObjectFind(ObjChartID,name)<0 && !ObjectCreate(ObjChartID,name,ObjectType,subwindow_id,t1,p1,t2,p2))
	      {
	         Print(__FUNCTION__,": failed to create line object! Error code = ",GetLastError());
	      }
	   
	      switch(ObjectType)
	      {
	         case OBJ_VLINE: {t1=1; break;}
	         case OBJ_HLINE: {p1=1; break;}
	         case OBJ_TREND: {t1=1; p1=1; t2=1; p2=1; break;}
	         case OBJ_TRENDBYANGLE: {t1=1; p1=1; break;}
	         case OBJ_CYCLES: {t1=1; p1=1; t2=1; p2=1; break;}
	      }
	      
	      if (t1==1) {t1=_time(3, 0, "00:00", 0, "", 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false); ObjectSetInteger(ObjChartID,name,OBJPROP_TIME,0,t1);}
	      if (t2==1) {t2=_time(3, 0, "00:00", 10, "", 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false); ObjectSetInteger(ObjChartID,name,OBJPROP_TIME,1,t2);}
	      if (p1==1) {p1=(_e_attrOpenPrice()-toDigits(6,CurrentSymbol())); ObjectSetDouble(ObjChartID,name,OBJPROP_PRICE,0,p1);}
	      if (p2==1) {p2=_candles("iClose", "id", 10, "00:00", CurrentSymbol(), CurrentTimeframe()); ObjectSetDouble(ObjChartID,name,OBJPROP_PRICE,1,p2);}
	      
	      ObjectSetInteger(ObjChartID,name,OBJPROP_STYLE,ObjStyle);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_COLOR,ObjColor);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_BACK,ObjBack);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_WIDTH,ObjWidth);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_SELECTABLE,ObjSelectable);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_SELECTED,ObjSelected);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_HIDDEN,ObjHidden);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_ZORDER,ObjZorder);
	      
	      ObjectSetDouble(ObjChartID,name,OBJPROP_ANGLE,ObjAngle);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_RAY,ObjRay);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_RAY_LEFT,ObjRayLeft);
	      ObjectSetInteger(ObjChartID,name,OBJPROP_RAY_RIGHT,ObjRayRight);
	      
	      ChartRedraw();
	   }
	}
	/* Orange output */
}
double _e_attrOpenPrice() {
	return(e_attrOpenPrice());
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #28 ((on chart) Mouse click on object&nbsp;) //
void block28(int _parent_=0)
{
	if (block28==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=28;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string NameFilterMode="name"; // Name filter mode
	string ObjName="RASELL"; // Object name(s)
	
	///////////////
	// Main code //
	///////////////
	
	bool gotonext=false;
	if (ChartEventType()==CHARTEVENT_OBJECT_CLICK) {
	   if (NameFilterMode=="name" || NameFilterMode=="names") {
	      string names[];
	      if (ObjName!="") {
	         StringExplode(",",ObjName,names);
	         int size=ArraySize(names);
	         for (int i=0; i<size; i++) {
	            if (ChartEventParameterString()==StringTrim(names[i])) {gotonext=true; break;}
	         }
	      }
	   }
	   else {gotonext=true;}
	}
	if (gotonext==true) {block32(28);} else {/* Yellow output */}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #32 (Counter: Pass once) //
void block32(int _parent_=0)
{
	if (block32==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=32;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	int CounterID=1; // Counter ID (for reset)
	
	///////////////
	// Main code //
	///////////////
	
	int passes=Counter(CounterID, "increment");
	
	if (passes==0) {block51(32);} else {/* Yellow output */}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #34 ((on chart) Mouse click on object&nbsp;) //
void block34(int _parent_=0)
{
	if (block34==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=34;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string NameFilterMode="name"; // Name filter mode
	string ObjName="RASLBE1"; // Object name(s)
	
	///////////////
	// Main code //
	///////////////
	
	bool gotonext=false;
	if (ChartEventType()==CHARTEVENT_OBJECT_CLICK) {
	   if (NameFilterMode=="name" || NameFilterMode=="names") {
	      string names[];
	      if (ObjName!="") {
	         StringExplode(",",ObjName,names);
	         int size=ArraySize(names);
	         for (int i=0; i<size; i++) {
	            if (ChartEventParameterString()==StringTrim(names[i])) {gotonext=true; break;}
	         }
	      }
	   }
	   else {gotonext=true;}
	}
	if (gotonext==true) {block36(34);} else {/* Yellow output */}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #36 (Modify stops of trades&nbsp;) //
void block36(int _parent_=0)
{
	if (block36==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=36;

	//////////////////////
	// 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
	int OrderMinutes=0; // Only older than
	string RelativeTo="openprice"; // Price relative to
	string NewSLTPmode="fixed";
	double NewStopLoss=-1; // New Stop Loss
	double NewStopLossPercent=50; // New SL (% of itself)
	double NewTakeProfit=0; // New Take Profit
	double NewTakeProfitPercent=50; // New TP (% of itself)
	color LevelColor=DeepPink; // Level color
	
	///////////////
	// Main code //
	///////////////
	
	int modified_count=0;
	int errors_count=0;
	for (int pos=OrdersTotal()-1; pos>=0; pos--) {
	   if (OrderSelect(pos,SELECT_BY_POS,MODE_TRADES)) {
	      if (FilterOrderBy(OrdersScope,OrdersGroup, SymbolScope,SYMBOL, BuysOrSells)) {
	         datetime time_diff = TimeCurrent()-attrOpenTime();
	         if (time_diff < 0) {time_diff = 0;} // this actually happens sometimes
	         if (time_diff >= 60*OrderMinutes)
	         {
	            SetSymbol(attrSymbol());
	            
	            /////
	            // New Price level
	            double PriceLevel=0;
	            if (attrType()==OP_BUY) {PriceLevel=SymbolAsk();}
	            else                     {PriceLevel=SymbolBid();}
	            if (RelativeTo=="openprice") {PriceLevel=attrOpenPrice();}
	            // New Price level
	            /////
	
	            /////
	            // New Stop Loss and Take Profit
	            double SL=0; double TP=0;
	            if (NewSLTPmode=="fixed") {
	               SL=toDigits(NewStopLoss);
	               TP=toDigits(NewTakeProfit);
	               if (attrType()==OP_BUY) {
	                  if (SL!=0) {SL=PriceLevel-SL;}
	                  if (TP!=0) {TP=PriceLevel+TP;}
	               }
	               else {
	                  if (SL!=0) {SL=PriceLevel+SL;}
	                  if (TP!=0) {TP=PriceLevel-TP;}
	               }
	            }
	            else if (NewSLTPmode=="percent") {
	               if (attrType()==OP_BUY) {
	                  SL=((attrOpenPrice()-attrStopLoss())*NewStopLossPercent)/100;
	                  TP=((attrTakeProfit()-attrOpenPrice())*NewTakeProfitPercent)/100;
	                  SL=PriceLevel-SL;
	                  TP=PriceLevel+TP;
	               }
	               else {
	                  SL=((attrStopLoss()-attrOpenPrice())*NewStopLossPercent)/100;
	                  TP=((attrOpenPrice()-attrTakeProfit())*NewTakeProfitPercent)/100;
	                  SL=PriceLevel+SL;
	                  TP=PriceLevel-TP;
	               }
	            }
	            else if (NewSLTPmode=="function") {
	               SL=_iAC(CurrentSymbol(), CurrentTimeframe(), 0);
	               TP=_value(50);
	            }
	            SL=NormalizeDouble(SL,SymbolDigits());
	            TP=NormalizeDouble(TP,SymbolDigits());
	            // New Stop Loss and Take Profit
	            /////
	            
	            if (SL!=NormalizeDouble(attrStopLoss(),SymbolDigits()) || TP!=NormalizeDouble(attrTakeProfit(),SymbolDigits()))
	            {
	               if (ModifyStops(attrTicket(),SL,TP,LevelColor)) {modified_count++;} else {errors_count++;}
	            }
	         }
	      }
	   }
	}
	
	/* Orange output */
}
double _iAC(string SYMBOL, int TIMEFRAME, int SHIFT) {
	SHIFT=SHIFT+IndicatorMoreShift();
	double retval=iAC(SYMBOL,TIMEFRAME,SHIFT);
	SetLastIndicatorData(retval,SYMBOL,TIMEFRAME,SHIFT);
	return(retval);
}
double _value(double Value) {
	return(Value);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #37 ((on chart) Mouse click on object&nbsp;) //
void block37(int _parent_=0)
{
	if (block37==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=37;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string NameFilterMode="name"; // Name filter mode
	string ObjName="RAClose 1/4"; // Object name(s)
	
	///////////////
	// Main code //
	///////////////
	
	bool gotonext=false;
	if (ChartEventType()==CHARTEVENT_OBJECT_CLICK) {
	   if (NameFilterMode=="name" || NameFilterMode=="names") {
	      string names[];
	      if (ObjName!="") {
	         StringExplode(",",ObjName,names);
	         int size=ArraySize(names);
	         for (int i=0; i<size; i++) {
	            if (ChartEventParameterString()==StringTrim(names[i])) {gotonext=true; break;}
	         }
	      }
	   }
	   else {gotonext=true;}
	}
	if (gotonext==true) {block38(37);} else {/* Yellow output */}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #38 (close (partially)&nbsp;) //
void block38(int _parent_=0)
{
	if (block38==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=38;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string PartVolMode="percent-initial"; // Volume mode
	double PartVolLots=0.05; // Volume size
	double PartVolPercent=25; // Volume size
	double Slippage=4; // Slippage
	color ArrowColor=DeepPink; // Arrow color
	
	///////////////
	// Main code //
	///////////////
	
	if (FXD_BREAK==true) {return;}
	LoopedResume();
	SetSymbol(attrSymbol());
	
	//-- lots to close ------------------------------------------------------------------------------------------
	double lots=0;
	
	     if (PartVolMode=="fixed")            {lots=PartVolLots;}
	else if (PartVolMode=="percent")          {lots=(attrLots()*PartVolPercent)/100;}
	else if (PartVolMode=="percent-initial")  {lots=(attrLotsInitial()*PartVolPercent)/100;}
	
	if (PartVolPercent>100) {lots=attrLots();}
	
	//-- partial close ------------------------------------------------------------------------------------------
	bool success=CloseTradePartial(attrTicket(),lots,Slippage,ArrowColor);
	
	if (success) {/* Orange output */} else {/* Gray output */}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #45 ((on chart) Mouse click on object&nbsp;) //
void block45(int _parent_=0)
{
	if (block45==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=45;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string NameFilterMode="name"; // Name filter mode
	string ObjName="RAClose 1/2"; // Object name(s)
	
	///////////////
	// Main code //
	///////////////
	
	bool gotonext=false;
	if (ChartEventType()==CHARTEVENT_OBJECT_CLICK) {
	   if (NameFilterMode=="name" || NameFilterMode=="names") {
	      string names[];
	      if (ObjName!="") {
	         StringExplode(",",ObjName,names);
	         int size=ArraySize(names);
	         for (int i=0; i<size; i++) {
	            if (ChartEventParameterString()==StringTrim(names[i])) {gotonext=true; break;}
	         }
	      }
	   }
	   else {gotonext=true;}
	}
	if (gotonext==true) {block46(45);} else {/* Yellow output */}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #46 (close (partially)&nbsp;) //
void block46(int _parent_=0)
{
	if (block46==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=46;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string PartVolMode="percent-initial"; // Volume mode
	double PartVolLots=0.05; // Volume size
	double PartVolPercent=50; // Volume size
	double Slippage=4; // Slippage
	color ArrowColor=DeepPink; // Arrow color
	
	///////////////
	// Main code //
	///////////////
	
	if (FXD_BREAK==true) {return;}
	LoopedResume();
	SetSymbol(attrSymbol());
	
	//-- lots to close ------------------------------------------------------------------------------------------
	double lots=0;
	
	     if (PartVolMode=="fixed")            {lots=PartVolLots;}
	else if (PartVolMode=="percent")          {lots=(attrLots()*PartVolPercent)/100;}
	else if (PartVolMode=="percent-initial")  {lots=(attrLotsInitial()*PartVolPercent)/100;}
	
	if (PartVolPercent>100) {lots=attrLots();}
	
	//-- partial close ------------------------------------------------------------------------------------------
	bool success=CloseTradePartial(attrTicket(),lots,Slippage,ArrowColor);
	
	if (success) {/* Orange output */} else {/* Gray output */}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #47 ((on chart) Mouse click on object&nbsp;) //
void block47(int _parent_=0)
{
	if (block47==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=47;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string NameFilterMode="name"; // Name filter mode
	string ObjName="RAClose All"; // Object name(s)
	
	///////////////
	// Main code //
	///////////////
	
	bool gotonext=false;
	if (ChartEventType()==CHARTEVENT_OBJECT_CLICK) {
	   if (NameFilterMode=="name" || NameFilterMode=="names") {
	      string names[];
	      if (ObjName!="") {
	         StringExplode(",",ObjName,names);
	         int size=ArraySize(names);
	         for (int i=0; i<size; i++) {
	            if (ChartEventParameterString()==StringTrim(names[i])) {gotonext=true; break;}
	         }
	      }
	   }
	   else {gotonext=true;}
	}
	if (gotonext==true) {block48(47);} else {/* Yellow output */}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #48 (Close trades&nbsp;) //
void block48(int _parent_=0)
{
	if (block48==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=48;

	//////////////////////
	// 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="sells"; // Filter by type
	int OrderMinutes=0; // Only older than
	double Slippage=4; // Slippage
	color ArrowColor=DeepPink; // Arrow color
	
	///////////////
	// Main code //
	///////////////
	
	int closed_count=0;
	bool finished=false;
	while (finished==false) {
	   int count=0;
	   for (int pos=OrdersTotal()-1; pos>=0; pos--) {
	      if (OrderSelect(pos,SELECT_BY_POS,MODE_TRADES)) {
	         if (FilterOrderBy(OrdersScope,OrdersGroup, SymbolScope,SYMBOL, BuysOrSells)) {
	            datetime time_diff = TimeCurrent()-attrOpenTime();
	            if (time_diff < 0) {time_diff = 0;} // this actually happens sometimes
	            if (time_diff >= 60*OrderMinutes)
	            {
	               if (CloseTrade(attrTicket(),Slippage,ArrowColor)) {closed_count++;}
	               count++;
	            }
	         }
	      }
	   }
	   if (count==0) {finished=true;}
	}
	
	/* Orange output */
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// fxDreema block #51 (Sell now&nbsp;) //
void block51(int _parent_=0)
{
	if (block51==false || FXD_BREAK==true) {return;}
	FXD_CURRENT_FUNCTION_ID=51;

	//////////////////////
	// Input parameters //
	//////////////////////
	
	string OrdersGroup=""; // Group # (empty=Default)
	string SYMBOL=CurrentSymbol(); // Market (empty=Current)
	string VolumeMode="freemarginRisk"; // Money management
	double VolumeSize=0.1; // Lot size
	double VolumeSizeRisk=50; // Risk fixed amount of money
	double VolumeRisk=inp51_VolumeRisk; // Risk percent
	double VolumePercent=100; // Volume size
	double VolumeBlockPercent=3; // Block % of Balance
	double FixedRatioUnitSize=0.01; // Fixed Ratio: Unit size
	double FixedRatioDelta=20; // Fixed Ratio: Delta parameter
	double mmMgInitialLots=0.1; // Initial volume
	double mmMgMultiplyOnLoss=2; // Multiply on loss
	double mmMgMultiplyOnProfit=1; // Multiply on profit
	double mmMgAddLotsOnLoss=0; // Add lots on loss
	double mmMgAddLotsOnProfit=0; // Add lots on profit
	int mmMgResetOnLoss=0; // Reset after how many losses?
	int mmMgResetOnProfit=1; // Reset after how many profits?
	double mm1326InitialLots=0.1; // Initial volume
	bool mm1326Reverse=false; // Reverse 1-3-2-6?
	double mmFiboInitialLots=0.1; // Initial volume
	double mmDalembertInitialLots=0.1; // Initial volume
	bool mmDalembertReverse=false; // Reverse D'Alembert
	double mmLabouchereInitialLots=0.1; // Initial volume
	string mmLabouchereList="1,2,3,4,5,6"; // List of numbers
	bool mmLabouchereReverse=false; // Reverse Labouchere
	double mmSeqBaseLots=0.1; // Base volume
	string mmSeqOnLoss="3,2,6"; // Sequence on loss
	string mmSeqOnProfit="1"; // Sequence on profit
	bool mmSeqReverse=false; // Reverse system?
	double VolumeUpperLimit=0; // Volume upper limit
	string StopLossMode="dynamicLevel"; // Stop-Loss mode
	double StopLossPips=100; // in pips...
	double StopLossPercentTP=100; // % of Take-Profit
	string TakeProfitMode="fixed"; // Take-Profit mode
	double TakeProfitPips=inp51_TakeProfitPips; // in pips...
	double TakeProfitPercentSL=100; // % of Stop-Loss
	string ExpMode="GTC"; // Expiration mode
	int ExpDays=0; // Days
	int ExpHours=1; // Hours
	int ExpMinutes=0; // Minutes
	double Slippage=4; // Slippage
	string MyComment="Short trade"; // Comment
	color ArrowColorSell=Red; // Arrow color
	
	///////////////
	// Main code //
	///////////////
	
	SetSymbol(SYMBOL);
	
	//-- stops ------------------------------------------------------------------
	double sll=0, slp=0, tpl=0, tpp=0;
	
	     if (StopLossMode=="fixed")        {slp=StopLossPips;}
	else if (StopLossMode=="dynamicPips")  {slp=_value(100);}
	else if (StopLossMode=="dynamicDigits"){slp=toPips(_value(0.0100),SYMBOL);}
	else if (StopLossMode=="dynamicLevel") {sll=_value(inp51_dlStopLoss_Value);}
	
	     if (TakeProfitMode=="fixed")         {tpp=TakeProfitPips;}
	else if (TakeProfitMode=="dynamicPips")   {tpp=_value(100);}
	else if (TakeProfitMode=="dynamicDigits") {tpp=toPips(_value(0.0100),SYMBOL);}
	else if (TakeProfitMode=="dynamicLevel")  {tpl=_value(1);}
	
	if (StopLossMode == "percentTP") {
	   if (tpp > 0) {slp = tpp*StopLossPercentTP/100;}
	   if (tpl > 0) {slp = toPips(MathAbs(SymbolAsk(SYMBOL) - tpl), SYMBOL)*StopLossPercentTP/100;}
	}
	if (TakeProfitMode == "percentSL") {
	   if (slp > 0) {tpp = slp*TakeProfitPercentSL/100;}
	   if (sll > 0) {tpp = toPips(MathAbs(SymbolAsk(SYMBOL) - sll), SYMBOL)*TakeProfitPercentSL/100;}
	}
	
	//-- lots -------------------------------------------------------------------
	double lots=0;
	double pre_sll=sll; if (pre_sll==0) {pre_sll=SymbolBid(SYMBOL);}
	double pre_sl_pips=toPips((pre_sll+toDigits(slp,SYMBOL))-SymbolBid(SYMBOL));
	
	     if (VolumeMode=="fixed")             {lots=DynamicLots(VolumeMode, VolumeSize);}
	else if (VolumeMode=="block-equity")      {lots=DynamicLots(VolumeMode, VolumeBlockPercent);}
	else if (VolumeMode=="block-balance")     {lots=DynamicLots(VolumeMode, VolumeBlockPercent);}
	else if (VolumeMode=="block-freemargin")  {lots=DynamicLots(VolumeMode, VolumeBlockPercent);}
	else if (VolumeMode=="equity")            {lots=DynamicLots(VolumeMode, VolumePercent);}
	else if (VolumeMode=="balance")           {lots=DynamicLots(VolumeMode, VolumePercent);}
	else if (VolumeMode=="freemargin")        {lots=DynamicLots(VolumeMode, VolumePercent);}
	else if (VolumeMode=="equityRisk")        {lots=DynamicLots(VolumeMode, VolumeRisk, pre_sl_pips);}
	else if (VolumeMode=="balanceRisk")       {lots=DynamicLots(VolumeMode, VolumeRisk, pre_sl_pips);}
	else if (VolumeMode=="freemarginRisk")    {lots=DynamicLots(VolumeMode, VolumeRisk, pre_sl_pips);}
	else if (VolumeMode=="fixedRisk")         {lots=DynamicLots(VolumeMode, VolumeSizeRisk, pre_sl_pips);}
	else if (VolumeMode=="fixedRatio")        {lots=DynamicLots(VolumeMode, FixedRatioUnitSize, FixedRatioDelta);}
	else if (VolumeMode=="dynamic")           {lots=AlignLots(_value(0.1));}
	else if (VolumeMode=="1326")              {lots=Bet1326(OrdersGroup, SYMBOL, mm1326InitialLots, mm1326Reverse);}
	else if (VolumeMode=="fibonacci")         {lots=BetFibonacci(OrdersGroup, SYMBOL, mmFiboInitialLots);}
	else if (VolumeMode=="dalembert")         {lots=BetDalembert(OrdersGroup, SYMBOL, mmDalembertInitialLots, mmDalembertReverse);}
	else if (VolumeMode=="labouchere")        {lots=BetLabouchere(OrdersGroup, SYMBOL, mmLabouchereInitialLots, mmLabouchereList, mmLabouchereReverse);}
	else if (VolumeMode=="martingale")        {lots=BetMartingale(OrdersGroup, SYMBOL, mmMgInitialLots, mmMgMultiplyOnLoss, mmMgMultiplyOnProfit, mmMgAddLotsOnLoss, mmMgAddLotsOnProfit, mmMgResetOnLoss, mmMgResetOnProfit);}
	else if (VolumeMode=="sequence")          {lots=BetSequence(OrdersGroup, SYMBOL, mmSeqBaseLots, mmSeqOnLoss, mmSeqOnProfit, mmSeqReverse);}
	
	lots = AlignLots(lots, 0, VolumeUpperLimit);
	
	datetime exp = ExpirationTime(ExpMode,ExpDays,ExpHours,ExpMinutes,_time(0, 0, "00:00", 1, "", 0, 0, 0, 0, 12, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, true));
	
	//-- send -------------------------------------------------------------------
	int ticket=SellNow(SYMBOL, lots, sll, tpl, slp, tpp, Slippage, (MagicStart+(int)OrdersGroup), MyComment, ArrowColorSell, exp);
	
	if (ticket>0) {/* Orange output */} else {/* Gray 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);
}
double AlignLots(double lots, double lowerlots=0, double upperlots=0)
{
	string symbol=GetSymbol();

   double LotStep=MarketInfo(symbol,MODE_LOTSTEP);
   double LotSize=MarketInfo(symbol,MODE_LOTSIZE);
   double MinLots=MarketInfo(symbol,MODE_MINLOT);
   double MaxLots=MarketInfo(symbol,MODE_MAXLOT);
   double margin_required=MarketInfo(symbol,MODE_MARGINREQUIRED);
   
   //if (lots>MaxLots) {lots=lots/LotSize;}
   
   //double stepsize=0;
   //while(lots+0.000000001>stepsize){stepsize+=LotStep;}
   //lots=stepsize-LotStep;
   lots=MathRound(lots/LotStep)*LotStep;
   
   if (lots<MinLots) {lots=MinLots;}
   if (lots>MaxLots) {lots=MaxLots;}

   if (lowerlots > 0)
   {
      lowerlots = MathRound(lowerlots/LotStep)*LotStep;
      if (lots < lowerlots) {lots = lowerlots;}
   }
   if (upperlots > 0)
   {
      upperlots = MathRound(upperlots/LotStep)*LotStep;
      if (lots > upperlots) {lots = upperlots;}
   }
   
   return (lots);
}
double AlignStopLoss(
   string symbol,
   int type,
   double price,
   double slo=0, // original sl, used when modifying
   double sll=0,
   double slp=0,
   bool consider_freezelevel=false
   )
{
   double sl=0;

   if (MathAbs(sll)==EMPTY_VALUE) {sll=0;}
   if (MathAbs(slp)==EMPTY_VALUE) {slp=0;}
   if (sll==0 && slp==0) {return(0);} // no sl - return 0
   if (price<=0) {Print("AlignStopLoss() error: No price entered");return(-1);}
   
   double point   =MarketInfo(symbol,MODE_POINT);
   double digits  =MarketInfo(symbol,MODE_DIGITS);
   slp = slp*PipValue(symbol)*point;
   
   
   //-- buy-sell identifier ---------------------------------------------
   int bs=1;
   if (
      type==OP_BUY
      || type==OP_BUYSTOP
      || type==OP_BUYLIMIT
      )
   {
      bs=1;
   }
   else if (
      type==OP_SELL
      || type==OP_SELLSTOP
      || type==OP_SELLLIMIT
      )
   {
      bs=-1;
   }
   
   //-- prices that will be used ----------------------------------------
   double askbid=price;
   double bidask=price;
   
   if (type==OP_BUY || type==OP_SELL)
   {
      double ask =MarketInfo(symbol,MODE_ASK);
      double bid =MarketInfo(symbol,MODE_BID);
      
      askbid=ask;
      bidask=bid;
      if (bs<0) {
        askbid=bid;
        bidask=ask;
      }
   }
   
   //-- build sl level -------------------------------------------------- 
   if (sll==0 && slp!=0) {sll=price;}

   if (sll>0) {sl=sll-slp*bs;}
   
   if (sl<0) {return(-1);}
      
   sl=NormalizeDouble(sl,digits);
   slo = NormalizeDouble(slo,digits);
   if (sl == slo) {return sl;}
   
   //-- build limit levels ----------------------------------------------
   double minstops=MarketInfo(symbol,MODE_STOPLEVEL);
   if (consider_freezelevel==true) {
      int freezelevel=MarketInfo(symbol,MODE_FREEZELEVEL);
      if (freezelevel>minstops) {minstops=freezelevel;}
   }
   minstops=NormalizeDouble(minstops*point,digits);
      
   double sllimit=bidask-minstops*bs; // SL min price level
   
   //-- check and align sl, print errors --------------------------------
   //-- do not do it when the stop is the same as the original
   if (sl>0) {
      /*if (sl==askbid)
      {
         sl=0;
      }
      else */
      if ((bs>0 && sl>bidask) || (bs<0 && sl<bidask))
      {
         string abstr="";
         if (bs>0) {abstr="Bid";} else {abstr="Ask";}
         Print(
            "Error: Invalid SL requested (",
            DoubleToStr(sl,digits),
            " for ",abstr," price ",
            askbid,
            ")"
         );
         return(-1);
      }
      else if ((bs>0 && sl>sllimit) || (bs<0 && sl<sllimit))
      {
         if (USE_VIRTUAL_STOPS) {
            return(sl);
         }

         Print(
            "Warning: Too short SL requested (",
            DoubleToStr(sl,digits),
            " or ",
            DoubleToStr(MathAbs(sl-askbid)/point,0),
            " points), minimum will be taken (",
            DoubleToStr(sllimit,digits),
            " or ",
            DoubleToStr(MathAbs(askbid-sllimit)/point,0),
            " points)"
         );
         sl=sllimit;

         return(sl);
      }
   }
   
   // align by the ticksize
   double ticksize = MarketInfo(symbol, MODE_TICKSIZE);
   sl = MathRound(sl/ticksize)*ticksize;
   
   return(sl);
}
double AlignTakeProfit(
   string symbol,
   int type,
   double price,
   double tpo=0, // original tp, used when modifying
   double tpl=0,
   double tpp=0,
   bool consider_freezelevel=false
   )
{
   double tp=0;
   
   if (MathAbs(tpl)==EMPTY_VALUE) {tpl=0;}
   if (MathAbs(tpp)==EMPTY_VALUE) {tpp=0;}
   if (tpl==0 && tpp==0) {return(0);} // no tp - return 0
   if (price<=0) {Print("AlignTakeProfit() error: No price entered");return(-1);}

   double point   =MarketInfo(symbol,MODE_POINT);
   double digits  =MarketInfo(symbol,MODE_DIGITS);
   tpp=tpp*PipValue(symbol)*point;
   
   //-- buy-sell identifier ---------------------------------------------
   int bs=1;
   if (
      type==OP_BUY
      || type==OP_BUYSTOP
      || type==OP_BUYLIMIT
      )
   {
      bs=1;
   }
   else if (
      type==OP_SELL
      || type==OP_SELLSTOP
      || type==OP_SELLLIMIT
      )
   {
      bs=-1;
   }
   
   //-- prices that will be used ----------------------------------------
   double askbid=price;
   double bidask=price;
   
   if (type==OP_BUY || type==OP_SELL)
   {
      double ask =MarketInfo(symbol,MODE_ASK);
      double bid =MarketInfo(symbol,MODE_BID);
      
      askbid=ask;
      bidask=bid;
      if (bs<0) {
        askbid=bid;
        bidask=ask;
      }
   }
   
   //-- build tp level --------------------------------------------------- 
   if (tpl==0 && tpp!=0) {tpl=price;}

   if (tpl>0) {tp=tpl+tpp*bs;}
   
   if (tp<0) {return(-1);}

   tp=NormalizeDouble(tp,digits);
   tpo = NormalizeDouble(tpo,digits);
   if (tp == tpo) {return tp;}
    
   //-- build limit levels ----------------------------------------------
   double minstops=MarketInfo(symbol,MODE_STOPLEVEL);
   if (consider_freezelevel==true) {
      int freezelevel=MarketInfo(symbol,MODE_FREEZELEVEL);
      if (freezelevel>minstops) {minstops=freezelevel;}
   }
   minstops=NormalizeDouble(minstops*point,digits);
   
   double tplimit=bidask+minstops*bs; // TP min price level
   
   //-- check and align tp, print errors --------------------------------
   //-- do not do it when the stop is the same as the original
   if (tp>0) {
      /*if (tp==askbid)
      {
         tp=0;
      }
      else */
      if ((bs>0 && tp<bidask) || (bs<0 && tp>bidask))
      {
         string abstr="";
         if (bs>0) {abstr="Bid";} else {abstr="Ask";}
         Print(
            "Error: Invalid TP requested (",
            DoubleToStr(tp,digits),
            " for ",abstr," price ",
            askbid,
            ")"
            );
         return(-1);
      }
      else if ((bs>0 && tp<tplimit) || (bs<0 && tp>tplimit))
      {
         if (USE_VIRTUAL_STOPS) {
            return(tp);
         }

         Print(
            "Warning: Too short TP requested (",
            DoubleToStr(tp,digits),
            " or ",
            DoubleToStr(MathAbs(tp-askbid)/point,0),
            " points), minimum will be taken (",
            DoubleToStr(tplimit,digits),
            " or ",
            DoubleToStr(MathAbs(askbid-tplimit)/point,0),
            " points)"
         );
         tp=tplimit;
         return(tp);
      }
   }

   // align by the ticksize
   double ticksize = MarketInfo(symbol, MODE_TICKSIZE);
   tp = MathRound(tp/ticksize)*ticksize;

   return(tp);
}
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 ArrayStrip(double &array[], double value)
{
   bool stripped=false;
   int size=ArraySize(array);
   if (size>0)
   {
      int i=0; int x=0;
      for (i=0; i<size; i++)
      {
         if (array[i]!=value)
         {
            array[x]=array[i];
            x++;
         } else {
            stripped=true;  
         }
      }
      ArrayResize(array,x);
   }
   return (stripped);
}
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);
}
bool ArrayValue(double &array[], double value)
{
   bool founded=false;
   int size=ArraySize(array);
   for (int i=0; i<size; i++) {
      if (array[i]==value) {founded=true; break;}
   }
   if (founded==false) {
      ArrayResize(array,size+1);
      array[size]=value;
      return (true);
   } else {
      return (false);
   }
}
bool ArrayValue(int &array[], int value)
{
   bool founded=false;
   int size=ArraySize(array);
   for (int i=0; i<size; i++) {
      if (array[i]==value) {founded=true; break;}
   }
   if (founded==false) {
      ArrayResize(array,size+1);
      array[size]=value;
      return (true);
   } else {
      return (false);
   }
}
bool ArrayValue(string &array[], string value)
{
   bool founded=false;
   int size=ArraySize(array);
   for (int i=0; i<size; i++) {
      if (array[i]==value) {founded=true; break;}
   }
   if (founded==false) {
      ArrayResize(array,size+1);
      array[size]=value;
      return (true);
   } else {
      return (false);  
   }
}
double Bet1326(int group, string symbol, double initial_lots, bool reverse=false)
{  
   int pos=0;
   int total=0;
   double lots=0;
   double profit=0;
   int profit_or_loss=0; // 0 - unknown, 1 - profit, -1 - loss
   
   //-- try to get last lot size from running trades
   total=OrdersTotal();
   for (pos=total-1; pos>=0; pos--)
   {
      if (!OrderSelect(pos, SELECT_BY_POS, MODE_TRADES)) {continue;}
      if (OrderMagicNumber() != MagicStart+group) {continue;}
      if (OrderSymbol() != symbol) {continue;}
      if (TimeCurrent() - OrderOpenTime() < 3) {continue;}
      
      if (lots==0) {
         lots=OrderLots();
      }
      
      profit = OrderClosePrice()-OrderOpenPrice();
      profit = NormalizeDouble(profit, SymbolDigits(OrderSymbol()));
      if (IsOrderTypeSell()) {profit = -1*profit;}
      if (profit == 0) {
         return(lots);
      }
      
      if (profit<0) {profit_or_loss=-1;}
      else {profit_or_loss=1;}
      
      break;
   }
   
   //-- if no running trade was found, search in history trades
   if (lots==0)
   {
      total=OrdersHistoryTotal();
      for (pos=total-1; pos>=0; pos--)
      {
         if(!OrderSelect(pos, SELECT_BY_POS, MODE_HISTORY)) {continue;}
         if (OrderMagicNumber() != MagicStart+group) {continue;}
         if (OrderSymbol() != symbol) {continue;}
         
         if (lots==0) {
            lots=OrderLots();
         }
         
         profit = OrderClosePrice()-OrderOpenPrice();
         profit = NormalizeDouble(profit, SymbolDigits(OrderSymbol()));
         if (IsOrderTypeSell()) {profit = -1*profit;}
         if (profit == 0) {
            return(lots);
         }
         
         if (profit<0) {profit_or_loss=-1;}
         else {profit_or_loss=1;}
         
         break;
      }
   }
   
   //--
   if (initial_lots < MarketInfo(symbol,MODE_MINLOT)) {
      initial_lots = MarketInfo(symbol,MODE_MINLOT);  
   }

   if (lots==0) {lots = initial_lots;}
   else
   {
      if ((reverse==false && profit_or_loss==1) || (reverse==true && profit_or_loss==-1))
      {
         double div = lots/initial_lots;
         
         if (div < 1.5) {lots = initial_lots*3;}
         else if (div < 2.5) {lots = initial_lots*6;}
         else if (div < 3.5) {lots = initial_lots*2;}
         else {lots = initial_lots;}
      }
      else {
         lots = initial_lots;
      }
   }
   
   return lots;
}
double BetDalembert(int group, string symbol, double initial_lots, double reverse=false)
{  
   int pos=0;
   int total=0;
   double lots=0;
   double profit=0;
   int profit_or_loss=0; // 0 - unknown, 1 - profit, -1 - loss
   
   //-- try to get last lot size from running trades
   total=OrdersTotal();
   for (pos=total-1; pos>=0; pos--)
   {
      if (!OrderSelect(pos, SELECT_BY_POS, MODE_TRADES)) {continue;}
      if (OrderMagicNumber() != MagicStart+group) {continue;}
      if (OrderSymbol() != symbol) {continue;}
      if (TimeCurrent() - OrderOpenTime() < 3) {continue;}
      
      if (lots==0) {
         lots=OrderLots();
      }
      
      profit = OrderClosePrice()-OrderOpenPrice();
      profit = NormalizeDouble(profit, SymbolDigits(OrderSymbol()));
      if (IsOrderTypeSell()) {profit = -1*profit;}
      if (profit == 0) {
         return(lots);
      }
      
      if (profit<0) {profit_or_loss=-1;}
      else {profit_or_loss=1;}
      
      break;
   }
   
   //-- if no running trade was found, search in history trades
   if (lots==0)
   {
      total=OrdersHistoryTotal();
      for (pos=total-1; pos>=0; pos--)
      {
         if(!OrderSelect(pos, SELECT_BY_POS, MODE_HISTORY)) {continue;}
         if (OrderMagicNumber() != MagicStart+group) {continue;}
         if (OrderSymbol() != symbol) {continue;}
         
         if (lots==0) {
            lots=OrderLots();
         }
         
         profit = OrderClosePrice()-OrderOpenPrice();
         profit = NormalizeDouble(profit, SymbolDigits(OrderSymbol()));
         if (IsOrderTypeSell()) {profit = -1*profit;}
         if (profit == 0) {
            return(lots);
         }
         
         if (profit<0) {profit_or_loss=-1;}
         else {profit_or_loss=1;}
         
         break;
      }
   }
   
   //--
   if (initial_lots < MarketInfo(symbol,MODE_MINLOT)) {
      initial_lots = MarketInfo(symbol,MODE_MINLOT);  
   }

   if (lots==0) {lots = initial_lots;}
   else
   {
      if ((reverse==0 && profit_or_loss==1) || (reverse==1 && profit_or_loss==-1))
      {
         lots = lots - initial_lots;
         if (lots < initial_lots) {lots = initial_lots;}
      }
      else {
         lots = lots + initial_lots;
      }
   }
   
   return lots;
}
double BetFibonacci(
   int group,
   string symbol,
   double initial_lots
   )
{
   int pos=0;
   int total=0;
   double lots=0;
   double profit=0;
   int profit_or_loss=0; // 0 - unknown, 1 - profit, -1 - loss
   
   //-- try to get last lot size from running trades
   total=OrdersTotal();
   for (pos=total-1; pos>=0; pos--)
   {
      if (!OrderSelect(pos, SELECT_BY_POS, MODE_TRADES)) {continue;}
      if (OrderMagicNumber() != MagicStart+group) {continue;}
      if (OrderSymbol() != symbol) {continue;}
      if (TimeCurrent() - OrderOpenTime() < 3) {continue;}
      
      if (lots==0) {
         lots=OrderLots();
      }
      
      profit = OrderClosePrice()-OrderOpenPrice();
      profit = NormalizeDouble(profit, SymbolDigits(OrderSymbol()));
      if (IsOrderTypeSell()) {profit = -1*profit;}
      if (profit == 0) {
         return(lots);
      }
      
      if (profit<0) {profit_or_loss=-1;}
      else {profit_or_loss=1;}
      
      break;
   }
   
   //-- if no running trade was found, search in history trades
   if (lots==0)
   {
      total=OrdersHistoryTotal();
      for (pos=total-1; pos>=0; pos--)
      {
         if(!OrderSelect(pos, SELECT_BY_POS, MODE_HISTORY)) {continue;}
         if (OrderMagicNumber() != MagicStart+group) {continue;}
         if (OrderSymbol() != symbol) {continue;}
         
         if (lots==0) {
            lots=OrderLots();
         }
         
         profit = OrderClosePrice()-OrderOpenPrice();
         profit = NormalizeDouble(profit, SymbolDigits(OrderSymbol()));
         if (IsOrderTypeSell()) {profit = -1*profit;}
         if (profit == 0) {
            return(lots);
         }
         
         if (profit<0) {profit_or_loss=-1;}
         else {profit_or_loss=1;}
         
         break;
      }
   }

   //--
   if (initial_lots < MarketInfo(symbol,MODE_MINLOT)) {
      initial_lots = MarketInfo(symbol,MODE_MINLOT);  
   }

   if (lots==0) {lots = initial_lots;}
   else
   {  
      int fibo1=1, fibo2=0, fibo3=0, fibo4=0;
      double div = lots/initial_lots;
      
      if (div<=0) {div=1;}

      while(true)
      {
         fibo1=fibo1+fibo2;
         fibo3=fibo2;
         fibo2=fibo1-fibo2;
         fibo4=fibo2-fibo3;
         if (fibo1 > NormalizeDouble(div, 2)) {break;}
      }
      //Print("("+fibo1 + "+" + fibo2+"+"+fibo3+") > "+div);
      if (profit_or_loss==1)
      {
         if (fibo4<=0) {fibo4=1;}
         //Print("Profit "+lots+"*"+fibo4);
         lots=initial_lots*(fibo4);
      }
      else {
         //Print("Loss "+lots+"*"+fibo1+"+"+fibo2);
         lots=initial_lots*(fibo1);
      }
   }
   
   lots=NormalizeDouble(lots, 2);
   return lots;
}
double BetLabouchere(int group, string symbol, double initial_lots, string list_of_numbers, double reverse=false)
{   
   int pos=0;
   int total=0;
   double lots=0;
   double profit=0;
   int profit_or_loss=0; // 0 - unknown, 1 - profit, -1 - loss
   
   //-- try to get last lot size from running trades
   total=OrdersTotal();
   for (pos=total-1; pos>=0; pos--)
   {
      if (!OrderSelect(pos, SELECT_BY_POS, MODE_TRADES)) {continue;}
      if (OrderMagicNumber() != MagicStart+group) {continue;}
      if (OrderSymbol() != symbol) {continue;}
      if (TimeCurrent() - OrderOpenTime() < 3) {continue;}
      
      if (lots==0) {
         lots=OrderLots();
      }
      
      profit = OrderClosePrice()-OrderOpenPrice();
      profit = NormalizeDouble(profit, SymbolDigits(OrderSymbol()));
      if (IsOrderTypeSell()) {profit = -1*profit;}
      if (profit == 0) {
         return(lots);
      }
      
      if (profit<0) {profit_or_loss=-1;}
      else {profit_or_loss=1;}
      
      break;
   }
   
   //-- if no running trade was found, search in history trades
   if (lots==0)
   {
      total=OrdersHistoryTotal();
      for (pos=total-1; pos>=0; pos--)
      {
         if(!OrderSelect(pos, SELECT_BY_POS, MODE_HISTORY)) {continue;}
         if (OrderMagicNumber() != MagicStart+group) {continue;}
         if (OrderSymbol() != symbol) {continue;}
         
         if (lots==0) {
            lots=OrderLots();
         }
         
         profit = OrderClosePrice()-OrderOpenPrice();
         profit = NormalizeDouble(profit, SymbolDigits(OrderSymbol()));
         if (IsOrderTypeSell()) {profit = -1*profit;}
         if (profit == 0) {
            return(lots);
         }

         if (profit<0) {profit_or_loss=-1;}
         else {profit_or_loss=1;}
         
         break;
      }
   }
   
   //-- Labouchere stuff
   static int mem_group[];
   static string mem_list[];
   static int mem_ticket[];
   int start_again=false;
   
   //- get the list of numbers as it is stored in the memory, or store it
   int id=ArraySearch(mem_group, group);
   if (id == -1) {
      start_again=true;
      if (list_of_numbers=="") {list_of_numbers="1";}
      id = ArraySize(mem_group);
      ArrayResize(mem_group, id+1, id+1);
      ArrayResize(mem_list, id+1, id+1);
      ArrayResize(mem_ticket, id+1, id+1);
      mem_group[id]=group;
      mem_list[id]=list_of_numbers;
   }
   
   if (mem_ticket[id]==OrderTicket()) {
      // the last known ticket (mem_ticket[id]) should be different than OderTicket() normally
      // when failed to create a new trade - the last ticket remains the same
      // so we need to reset
      mem_list[id]=list_of_numbers;
   }
   mem_ticket[id]=OrderTicket();
   
   //- now turn the string into integer array
   int list[];
   string listS[];
   StringExplode(",", mem_list[id], listS);
   ArrayResize(list, ArraySize(listS));
   for (int s=0; s<ArraySize(listS); s++) {
      list[s]=StringToInteger(StringTrim(listS[s]));  
   }

   //-- 
   int size = ArraySize(list);

   if (initial_lots < MarketInfo(symbol,MODE_MINLOT)) {
      initial_lots = MarketInfo(symbol,MODE_MINLOT);  
   }

   if (lots==0) {
      start_again=true;
   }
   
   if (start_again==true)
   {
      if (size==1) {
         lots = initial_lots*list[0];
      } else {
         lots = initial_lots*(list[0]+list[size-1]);
      }
   }
   else 
   {
      if ((reverse==0 && profit_or_loss==1) || (reverse==1 && profit_or_loss==-1))
      {
         if (size==1) {
            lots=initial_lots*list[0];
            ArrayResize(list, 0);
         }
         else if (size==2) {
            lots = initial_lots*(list[0]+list[1]);
            ArrayResize(list, 0);
         }
         else if (size>2) {
            lots = initial_lots*(list[0]+list[size-1]);
            // Cancel first and last numbers in our list
            // shift array 1 step left
            for(pos=0; pos<size-1; pos++) {
               list[pos]=list[pos+1];
            }
            ArrayResize(list,ArraySize(list)-2); // remove last 2 elements		
         }
         if (lots < initial_lots) {lots = initial_lots;}
      }
      else {
         if (size>1)
         {
            ArrayResize(list, size+1);
            list[size]=list[0]+list[size-1];
            lots = initial_lots*(list[0]+list[size]);
         } else {
            lots = initial_lots*list[0];
         }
         if (lots < initial_lots) {lots = initial_lots;}
      }

   }
   
   Print("Labouchere (for group "+id+") current list of numbers:"+StringImplode(",", list));
   size=ArraySize(list);
   if (size==0) {
      ArrayStripKey(mem_group, id);
      ArrayStripKey(mem_list, id);
      ArrayStripKey(mem_ticket, id);
   } else {
      mem_list[id]=StringImplode(",", list);
   }

   return lots;
}
double BetMartingale(
   int group,
   string symbol,
   double initial_lots,
   double multiply_on_loss,
   double multiply_on_profit,
   double add_on_loss,
   double add_on_profit,
   int reset_on_loss,
   int reset_on_profit
   )
{
   int pos=0;
	int total=0;
   double lots=0;
   double profit=0;
   int profit_or_loss=0; // 0 - unknown, 1 - profit, -1 - loss
   int in_a_row=0;
   
   //-- try to get last lot size from running trades
   total=OrdersTotal();
   for (pos=total-1; pos>=0; pos--)
   {
      if (!OrderSelect(pos, SELECT_BY_POS, MODE_TRADES)) {continue;}
      if (OrderMagicNumber() != MagicStart+group) {continue;}
      if (OrderSymbol() != symbol) {continue;}
      if (TimeCurrent() - OrderOpenTime() < 3) {continue;}

      if (lots==0) {
         lots=OrderLots();
      }
      
      profit = OrderClosePrice()-OrderOpenPrice();
      profit = NormalizeDouble(profit, SymbolDigits(OrderSymbol()));
      if (IsOrderTypeSell()) {profit = -1*profit;}
      if (profit == 0) {
         return(lots);
      }
      
      if (profit_or_loss == 0)
      {
         
         if (profit<0) {profit_or_loss=-1;}
         else {profit_or_loss=1;}
      }
      else {
              if (profit_or_loss==1 && profit<0) {break;}
         else if (profit_or_loss==-1 && profit>=0) {break;}
      }
      
      in_a_row++;
   }
   
   //-- if no running trade was found, search in history trades
   if (lots==0)
   {
      total=OrdersHistoryTotal();
      for (pos=total-1; pos>=0; pos--)
      {
         if(!OrderSelect(pos, SELECT_BY_POS, MODE_HISTORY)) {continue;}
         if (OrderMagicNumber() != MagicStart+group) {continue;}
         if (OrderSymbol() != symbol) {continue;}
         
         if (lots==0) {
            lots=OrderLots();
         }
         
         profit = OrderClosePrice()-OrderOpenPrice();
         profit = NormalizeDouble(profit, SymbolDigits(OrderSymbol()));
         if (IsOrderTypeSell()) {profit = -1*profit;}
         if (profit == 0) {
            return(lots);
         }
         
         if (profit_or_loss == 0)
         {
            if (profit<0) {profit_or_loss=-1;}
            else {profit_or_loss=1;}
         }
         else {
                 if (profit_or_loss==1 && profit<0) {break;}
            else if (profit_or_loss==-1 && profit>=0) {break;}
         }
         
         in_a_row++;
      }
   }

   //--
   /*
   if (initial_lots < MarketInfo(symbol,MODE_MINLOT)) {
      initial_lots = MarketInfo(symbol,MODE_MINLOT);  
   }*/

   if (lots==0) {lots = initial_lots;}
   else {
      if (profit_or_loss==1)
      {
         if (reset_on_profit>0 && in_a_row >= reset_on_profit) {
            lots=initial_lots;  
         }
         else {
            if (multiply_on_profit<=0) {multiply_on_profit=1;}
            lots=(lots*multiply_on_profit) + add_on_profit;
         }
      }
      else {
         if (reset_on_loss>0 && in_a_row >= reset_on_loss) {
            lots=initial_lots;  
         }
         else {
            if (multiply_on_loss<=0) {multiply_on_loss=1;}
            lots=(lots*multiply_on_loss) + add_on_loss;
         }
      }
   }
   
   return lots;
}
double BetSequence(int group, string symbol, double initial_lots, string sequence_on_loss, string sequence_on_profit, bool reverse=false)
{  
   int pos=0;
   int total=0;
   double lots=0;
   int size=0;
   double profit=0;
   int profit_or_loss=0; // 0 - unknown, 1 - profit, -1 - loss
   
   //-- try to get last lot size from running trades
   total=OrdersTotal();
   for (pos=total-1; pos>=0; pos--)
   {
      if (!OrderSelect(pos, SELECT_BY_POS, MODE_TRADES)) {continue;}
      if (OrderMagicNumber() != MagicStart+group) {continue;}
      if (OrderSymbol() != symbol) {continue;}
      if (TimeCurrent() - OrderOpenTime() < 3) {continue;}
      
      if (lots==0) {
         lots=OrderLots();
      }
      
      profit = OrderClosePrice()-OrderOpenPrice();
      profit = NormalizeDouble(profit, SymbolDigits(OrderSymbol()));
      if (IsOrderTypeSell()) {profit = -1*profit;}
      if (profit == 0) {
         return(lots);
      }
      
      if (profit<0) {profit_or_loss=-1;}
      else {profit_or_loss=1;}
      
      break;
   }
   
   //-- if no running trade was found, search in history trades
   if (lots==0)
   {
      total=OrdersHistoryTotal();
      for (pos=total-1; pos>=0; pos--)
      {
         if(!OrderSelect(pos, SELECT_BY_POS, MODE_HISTORY)) {continue;}
         if (OrderMagicNumber() != MagicStart+group) {continue;}
         if (OrderSymbol() != symbol) {continue;}
         
         if (lots==0) {
            lots=OrderLots();
         }
         
         profit = OrderClosePrice()-OrderOpenPrice();
         profit = NormalizeDouble(profit, SymbolDigits(OrderSymbol()));
         if (IsOrderTypeSell()) {profit = -1*profit;}
         if (profit == 0) {
            return(lots);
         }
         
         if (profit<0) {profit_or_loss=-1;}
         else {profit_or_loss=1;}
         
         break;
      }
   }
   
   //-- Sequence stuff
   static int mem_group[];
   static string mem_list_loss[];
   static string mem_list_profit[];
   static int mem_ticket[];
   
   //- get the list of numbers as it is stored in the memory, or store it
   int id=ArraySearch(mem_group, group);
   if (id == -1)
   {
      if (sequence_on_loss=="") {sequence_on_loss="1";}
      if (sequence_on_profit=="") {sequence_on_profit="1";}
      id = ArraySize(mem_group);
      ArrayResize(mem_group, id+1, id+1);
      ArrayResize(mem_list_loss, id+1, id+1);
      ArrayResize(mem_list_profit, id+1, id+1);
      ArrayResize(mem_ticket, id+1, id+1);
      mem_group[id]        =group;
      mem_list_loss[id]    =sequence_on_loss;
      mem_list_profit[id]  =sequence_on_profit;
   }
   
   bool loss_reset=false;
   bool profit_reset=false;
   if (profit_or_loss==-1 && mem_list_loss[id]=="") {
      loss_reset=true;
      mem_list_profit[id]="";
   }
   if (profit_or_loss==1 && mem_list_profit[id]=="") {
      profit_reset=true;
      mem_list_loss[id]="";
   }
   
   if (profit_or_loss==1 || mem_list_loss[id]=="") {
      mem_list_loss[id]=sequence_on_loss;
      if (loss_reset) {mem_list_loss[id]="1,"+mem_list_loss[id];}
      
   }
   if (profit_or_loss==-1 ||mem_list_profit[id]=="") {
      mem_list_profit[id]=sequence_on_profit;
      if (profit_reset) {mem_list_profit[id]="1,"+mem_list_profit[id];}
   }
   
   if (mem_ticket[id]==OrderTicket()) {
      // the last known ticket (mem_ticket[id]) should be different than OderTicket() normally
      // when failed to create a new trade - the last ticket remains the same
      // so we need to reset
      mem_list_loss[id]=sequence_on_loss;
      mem_list_profit[id]=sequence_on_profit;
   }
   mem_ticket[id]=OrderTicket();
   
   //- now turn the string into integer array
   int s=0;
   int list_loss[];
   int list_profit[];
   string listS[];
   StringExplode(",", mem_list_loss[id], listS);
   ArrayResize(list_loss, ArraySize(listS), ArraySize(listS));
   for (s=0; s<ArraySize(listS); s++) {
      list_loss[s]=(int)StringToInteger(StringTrim(listS[s]));  
   }
   StringExplode(",", mem_list_profit[id], listS);
   ArrayResize(list_profit, ArraySize(listS), ArraySize(listS));
   for (s=0; s<ArraySize(listS); s++) {
      list_profit[s]=(int)StringToInteger(StringTrim(listS[s]));  
   }

   //--
   if (initial_lots < MarketInfo(symbol,MODE_MINLOT)) {
      initial_lots = MarketInfo(symbol,MODE_MINLOT);  
   }

   if (lots==0) {lots = initial_lots;}
   else
   {
      if ((reverse==false && profit_or_loss==1) || (reverse==true && profit_or_loss==-1))
      {
         lots = initial_lots*list_profit[0];
         // shift array 1 step left
         size=ArraySize(list_profit);
         for(pos=0; pos<size-1; pos++) {
            list_profit[pos]=list_profit[pos+1];
         }
         if (size>0) {
            ArrayResize(list_profit, size-1, size-1);
            mem_list_profit[id]=StringImplode(",", list_profit);
         }
         // reset the opposite sequence
         //mem_list_loss[id]="";
      }
      else {
         
         lots = initial_lots*list_loss[0];
         // shift array 1 step left
         size=ArraySize(list_loss);
         for(pos=0; pos<size-1; pos++) {
            list_loss[pos]=list_loss[pos+1];
         }
         if (size>0) {
            ArrayResize(list_loss, size-1, size-1);
            mem_list_loss[id]=StringImplode(",", list_loss);
         }
         // reset the opposite sequence
         //mem_list_profit[id]="";
      }
   }
   
   return lots;
}
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.."));}
         if (!IsTesting()) {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.."));}
         if (!IsTesting()) {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.."));}
         if (!IsTesting()) {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.."));}
         if (!IsTesting()) {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.."));}
         if (!IsTesting()) {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);
}
bool CloseTradePartial(int ticket, double lots, double slippage, color arrowcolor)
{
   if (ticket!=attrTicket()) {
      if (!OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) {
         Print("Cannot close a trade: Trade #"+ticket+" is already closed or it does not exist"); 
         return(false);
      }
   }
   double old_sl=attrStopLoss();
   double old_tp=attrTakeProfit();
   
   WaitTradeContextIfBusy();
   
   if (lots>OrderLots()) {lots=OrderLots();}

   double lotstep=MarketInfo(OrderSymbol(), MODE_LOTSTEP);
   lots=MathRound(lots/lotstep)*lotstep;
   
   lots=AlignLots(lots);
   double old_lots=OrderLots();

   if (OrderClose(ticket,lots,attrClosePrice(),slippage*PipValue(attrSymbol()),arrowcolor))
   {
      if (USE_VIRTUAL_STOPS) {
         VirtualStopsDriver("clear",ticket);
      }
      if (lots!=old_lots) {
         int ticket_child = attrTicketChild(ticket);
         attrTicketInLoop(ticket_child);
         attrLotsClosed(lots);
         //Print("VS -> "+ (ticket_child) + " " +old_sl+" " +old_tp);
         VirtualStopsDriver("partial",ticket_child,old_sl,old_tp);
      }
      RegisterEvent("trade");
      return(true);
   } else {
      Print(ErrorMessage(GetLastError()));  
   }
   return(false);
}
int Counter(int id, string cmd="", int set_passes=0)
{
	static int idx[]; // index list
   static int pl[]; // passes list
   int size=0;
   int passes=0;
   int cnt_idx=ArraySearch(idx, id);
   
   if (cnt_idx==-1) {
      // Counter not found
      size=ArraySize(idx);
      ArrayResize(idx,size+1);
      ArrayResize(pl,size+1);
      idx[size]=id;
      pl[size]=0;
      cnt_idx=0;
   }
   passes=pl[cnt_idx];
   if (cmd!="") {
           if (cmd=="increment") {pl[cnt_idx]=pl[cnt_idx]+1;}
      else if (cmd=="reset") {pl[cnt_idx]=0;}
   }
   return(passes);
}
string CurrentSymbol(string symbol="")
{
   static string memory="";
   if (symbol!="") {memory=symbol;} else
   if (memory=="") {memory=Symbol();}
   return(memory);
}
int CurrentTimeframe(int tf=-1)
{
	static int memory=0;
   if (tf>=0) {memory=tf;}
   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, "0");
      }
   }
   
   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 DynamicLots(string mode="balance", double value=0, double sl=0, string align="align", double RJFR_initial_lots=0)
{
   double size=0;
   string symbol=GetSymbol();
   double LotStep=MarketInfo(symbol,MODE_LOTSTEP);
   double LotSize=MarketInfo(symbol,MODE_LOTSIZE);
   double MinLots=MarketInfo(symbol,MODE_MINLOT);
   double MaxLots=MarketInfo(symbol,MODE_MAXLOT);
   double TickValue=MarketInfo(symbol,MODE_TICKVALUE);
   double point=MarketInfo(symbol,MODE_POINT);
   double ticksize=MarketInfo(symbol,MODE_TICKSIZE);
   double margin_required=MarketInfo(symbol,MODE_MARGINREQUIRED);
   
   if (mode=="fixed" || mode=="lots")     {size=value;}
   else if (mode=="block-equity")      {size=(value/100)*AccountEquity()/margin_required;}
   else if (mode=="block-balance")     {size=(value/100)*AccountBalance()/margin_required;}
   else if (mode=="block-freemargin")  {size=(value/100)*AccountFreeMargin()/margin_required;}
   else if (mode=="equity")      {size=(value/100)*AccountEquity()/(LotSize*TickValue);}
   else if (mode=="balance")     {size=(value/100)*AccountBalance()/(LotSize*TickValue);}
   else if (mode=="freemargin")  {size=(value/100)*AccountFreeMargin()/(LotSize*TickValue);}
   else if (mode=="equityRisk")     {size=((value/100)*AccountEquity())/(sl*((TickValue/ticksize)*point)*PipValue(symbol));}
   else if (mode=="balanceRisk")    {size=((value/100)*AccountBalance())/(sl*((TickValue/ticksize)*point)*PipValue(symbol));}
   else if (mode=="freemarginRisk") {size=((value/100)*AccountFreeMargin())/(sl*((TickValue/ticksize)*point)*PipValue(symbol));}
   else if (mode=="fixedRisk")   {size=(value)/(sl*((TickValue/ticksize)*point)*PipValue(symbol));}
   else if (mode=="fixedRatio" || mode=="RJFR") {
      
      /////
      // Ryan Jones Fixed Ratio MM static data
      static double RJFR_start_lots=0;
      static double RJFR_delta=0;
      static double RJFR_units=1;
      static double RJFR_target_lower=0;
      static double RJFR_target_upper=0;
      /////
      
      if (RJFR_start_lots<=0) {RJFR_start_lots=value;}
      if (RJFR_start_lots<MinLots) {RJFR_start_lots=MinLots;}
      if (RJFR_delta<=0) {RJFR_delta=sl;}
      if (RJFR_target_upper<=0) {
         RJFR_target_upper=AccountEquity()+(RJFR_units*RJFR_delta);
         Print("Fixed Ratio MM: Units=>",RJFR_units,"; Delta=",RJFR_delta,"; Upper Target Equity=>",RJFR_target_upper);
      }
      if (AccountEquity()>=RJFR_target_upper)
      {
         while(true) {
            Print("Fixed Ratio MM going up to ",(RJFR_start_lots*(RJFR_units+1))," lots: Equity is above Upper Target Equity (",AccountEquity(),">=",RJFR_target_upper,")");
            RJFR_units++;
            RJFR_target_lower=RJFR_target_upper;
            RJFR_target_upper=RJFR_target_upper+(RJFR_units*RJFR_delta);
            Print("Fixed Ratio MM: Units=>",RJFR_units,"; Delta=",RJFR_delta,"; Lower Target Equity=>",RJFR_target_lower,"; Upper Target Equity=>",RJFR_target_upper);
            if (AccountEquity()<RJFR_target_upper) {break;}
         }
      }
      else if (AccountEquity()<=RJFR_target_lower)
      {
         while(true) {
         if (AccountEquity()>RJFR_target_lower) {break;}
            if (RJFR_units>1) {         
               Print("Fixed Ratio MM going down to ",(RJFR_start_lots*(RJFR_units-1))," lots: Equity is below Lower Target Equity | ", AccountEquity()," <= ",RJFR_target_lower,")");
               RJFR_target_upper=RJFR_target_lower;
               RJFR_target_lower=RJFR_target_lower-((RJFR_units-1)*RJFR_delta);
               RJFR_units--;
               Print("Fixed Ratio MM: Units=>",RJFR_units,"; Delta=",RJFR_delta,"; Lower Target Equity=>",RJFR_target_lower,"; Upper Target Equity=>",RJFR_target_upper);
            } else {break;}
         }
      }
      size=RJFR_start_lots*RJFR_units;
   }
   
   size=MathRound(size/LotStep)*LotStep;
   
   static bool alert_min_lots=false;
   if (size<MinLots && alert_min_lots==false) {
      alert_min_lots=true;
      Alert("You want to trade ",size," lot, but your broker's minimum is ",MinLots," lot. The trade/order will continue with ",MinLots," lot instead of ",size," lot. The same rule will be applied for next trades/orders with desired lot size lower than the minimum. You will not see this message again until you restart the program.");
   }
   
   if (align=="align") {
      if (size<MinLots) {size=MinLots;}
      if (size>MaxLots) {size=MaxLots;}
   }
   
   return (size);
}
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));
         }
      }
   }
}
datetime ExpirationTime(string mode="GTC",int days=0, int hours=0, int minutes=0, datetime custom=0)
{
	datetime expiration=TimeCurrent();
   if (mode=="GTC" || mode=="")   {expiration=0;}
   else if (mode=="today") {expiration=StrToTime(TimeYear(TimeCurrent())+"."+TimeMonth(TimeCurrent())+"."+TimeDay(TimeCurrent()))+86400;}
   else if (mode=="specified") {
      expiration=0;
      if ((days + hours + minutes)>0) {
         expiration=TimeCurrent()+(86400*days)+(3600*hours)+(60*minutes);
      }
   }
   else
   {
      if (custom <= TimeCurrent()) {
         if (custom < 31557600) {
            custom = TimeCurrent()+custom;
         }
         else {
            custom=0;
         }
      }
      expiration = custom;
   }
   return(expiration);
}
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 InArray(double &array[], double value)
{
   bool founded=false;
   int size=ArraySize(array);
   for (int i=0; i<size; i++) {
      if (array[i]==value) {founded=true; break;}  
   }
   return (founded);
}
bool InArray(int &array[], int value)
{
   bool founded=false;
   int size=ArraySize(array);
   for (int i=0; i<size; i++) {
      if (array[i]==value) {founded=true; break;}  
   }
   return (founded);
}
bool InArray(string &array[], string value)
{
   bool founded=false;
   int size=ArraySize(array);
   for (int i=0; i<size; i++) {
      if (array[i]==value) {founded=true; break;}  
   }
   return (founded);
}
int IndicatorMoreShift(bool set=false, int shift=0)
{
	static int mem;
   if (set==true) {mem=shift;}
   else {
      int return_val=mem; mem=0; // reset
      return(return_val);
   }
   return(mem);
}
bool IsOrderTypeSell() {
   if (
   OrderType()==OP_SELL
   ||
   OrderType()==OP_SELLSTOP
   ||
   OrderType()==OP_SELLLIMIT
   ) {return(true);}
   return(false);
}
int LastIndicatorShift(bool set=false, int shift=0)
{
   static int mem;
   if (set==true) {mem=shift;}
   return(mem);
}
string LastIndicatorSymbol(bool set=false, string symbol="")
{
	static string mem;
   if (set==true) {mem=symbol;}
   return(mem);
}
int LastIndicatorTimeframe(bool set=false, int timeframe=0)
{
   static int mem;
   if (set==true) {mem=timeframe;}
   return(mem);
}
double LastIndicatorValue(bool set=false, double value=0)
{
   static double mem;
   if (set==true) {mem=value;}
   return(mem);
}
int LoopedResume()
{
   if (attrTicketInLoop()>0 && attrTicketInLoop()!=attrTicket()) {
      //Alert(attrTicketInLoop());
      return(OrderSelect(attrTicketInLoop(),SELECT_BY_TICKET));
   }
   return(0);
   /*
   static int ticket;
   
   if (set==true) {
      if (attrTicket()>0) {ticket=attrTicket();}
      return(true);
   } else {
      if (ticket>0 && ticket!=attrTicket()) {
         OrderSelect(ticket,SELECT_BY_TICKET);
      }
      return(true);
   }
   
   return(false);*/
}
bool ModifyOrder(
   int ticket,
   double op,
   double sll=0,
   double tpl=0,
   double slp=0,
   double tpp=0,
   datetime exp=0,
   color clr=CLR_NONE,
   bool ontrade_event=true)
{
//-----------------------------------------------------------------------
   int bs=1;
   if (
         OrderType()==OP_SELL
      || OrderType()==OP_SELLSTOP
      || OrderType()==OP_SELLLIMIT
      )
   {bs=-1;} // Positive when Buy, negative when Sell

   while(true)
   {
      int time0=GetTickCount();
      
      WaitTradeContextIfBusy();
      
      if (!OrderSelect(ticket,SELECT_BY_TICKET)) {
         return(false);
      }
      
      string symbol     =OrderSymbol();
      int type          =OrderType();
      double ask        =MarketInfo(symbol,MODE_ASK);
      double bid        =MarketInfo(symbol,MODE_BID);
      double digits     =MarketInfo(symbol,MODE_DIGITS);
      double point      =MarketInfo(symbol,MODE_POINT);
      
      if (OrderType()<2) {op=OrderOpenPrice();} else {op=NormalizeDouble(op,digits);}
      sll=NormalizeDouble(sll,digits);
      tpl=NormalizeDouble(tpl,digits);
      if (op<0 || op>=EMPTY_VALUE)  {break;}
      if (sll<0) {break;}
      if (slp<0) {break;}
      if (tpl<0) {break;}
      if (tpp<0) {break;}
      
      //-- SL and TP ----------------------------------------------------
      double sl=0, tp=0, vsl=0, vtp=0;
      sl=AlignStopLoss(symbol, type, op, attrStopLoss(), sll, slp);
      if (sl<0) {break;}
      tp=AlignTakeProfit(symbol, type, op, attrTakeProfit(), tpl, tpp);
      if (tp<0) {break;}
      
      if (USE_VIRTUAL_STOPS)
      {
         //-- virtual SL and TP --------------------------------------------
         vsl=sl;
         vtp=tp;
         sl=0; tp=0;
      
         double askbid=ask;
         if (bs<0) {askbid=bid;}
         
         if (vsl>0 || USE_EMERGENCY_STOPS=="always") {
            if (EMERGENCY_STOPS_REL>0 || EMERGENCY_STOPS_ADD>0)
            {
               sl=vsl-EMERGENCY_STOPS_REL*MathAbs(askbid-vsl)*bs;
               if (sl<=0) {sl=askbid;}
               sl=sl-toDigits(EMERGENCY_STOPS_ADD,symbol)*bs;
            }
         }
         if (vtp>0 || USE_EMERGENCY_STOPS=="always") {
            if (EMERGENCY_STOPS_REL>0 || EMERGENCY_STOPS_ADD>0)
            {
               tp=vtp+EMERGENCY_STOPS_REL*MathAbs(vtp-askbid)*bs;
               if (tp<=0) {tp=askbid;}
               tp=tp+toDigits(EMERGENCY_STOPS_ADD,symbol)*bs;
            }
         }
         vsl=NormalizeDouble(vsl,digits);
         vtp=NormalizeDouble(vtp,digits);
      }
      sl=NormalizeDouble(sl,digits);
      tp=NormalizeDouble(tp,digits);

      //-- modify -------------------------------------------------------
      if (USE_VIRTUAL_STOPS) {
         if (vsl!=attrStopLoss() || vtp!=attrTakeProfit()) {
            VirtualStopsDriver("set", ticket, vsl, vtp, toPips(MathAbs(op-vsl), symbol), toPips(MathAbs(vtp-op), symbol));
         }
         int error=GetLastError();
      }
      bool success=false;
      //Print(op+"!=+"+NormalizeDouble(OrderOpenPrice(),digits));
      if (
            (OrderType()>1 && op!=NormalizeDouble(OrderOpenPrice(),digits))
         || sl!=NormalizeDouble(OrderStopLoss(),digits)
         || tp!=NormalizeDouble(OrderTakeProfit(),digits)
         || exp!=OrderExpiration()
      ) {
         success=OrderModify(ticket,op,sl,tp,exp,clr);
      }
         
      //-- error check --------------------------------------------------
      int erraction=CheckForTradingError(GetLastError(), "Modify error");
      switch(erraction)
      {
         case 0: break;    // no error
         case 1: continue; // overcomable error
         case 2: break;    // fatal error
      }
      
      //-- finish work --------------------------------------------------
      if (success==true) {
         if (!IsTesting() && !IsVisualMode()) Print("Operation details: Speed "+(GetTickCount()-time0)+" ms");
         if (ontrade_event == true)
         {
            OrderModified(ticket);
            RegisterEvent("trade");
         }
         if (OrderSelect(ticket,SELECT_BY_TICKET)) {}
         return(true);
      }
      
      break;
   }

   return(false);
}
bool ModifyStops(int ticket, double sl=-1, double tp=-1, color clr=CLR_NONE)
{
   return(ModifyOrder(ticket,attrOpenPrice(),sl,tp,0,0,attrExpiration(),clr));
}
int OCODriver()
{
	static int last_known_ticket = 0;
   static int orders1[];
   static int orders2[];
   int i, size;
   
   int total = OrdersTotal();
   
   for (int pos=total-1; pos>=0; pos--)
   {
      if (OrderSelect(pos,SELECT_BY_POS,MODE_TRADES))
      {
         int ticket = OrderTicket();
         
         //-- end here if we reach the last known ticket
         if (ticket == last_known_ticket) {break;}
         
         //-- set the last known ticket, only if this is the first iteration
         if (pos == total-1) {
            last_known_ticket = ticket;
         }
         
         //-- we are searching for pending orders, skip trades
         if (OrderType() <= OP_SELL) {continue;}
         
         //--
         if (StringSubstr(OrderComment(), 0, 5) == "[oco:")
         {
            int ticket_oco = StrToInteger(StringSubstr(OrderComment(), 5, StringLen(OrderComment())-1)); 
            
            bool found = false;
            size = ArraySize(orders2);
            for (i=0; i<size; i++)
            {
               if (orders2[i] == ticket_oco) {
                  found = true;
                  break;
               }
            }
            
            if (found == false) {
               ArrayResize(orders1, size+1);
               ArrayResize(orders2, size+1);
               orders1[size] = ticket_oco;
               orders2[size] = ticket;
            }
         }
      }
   }
   
   size = ArraySize(orders1);
   int dbremove = false;
   for (i=0; i<size; i++)
   {
      if (OrderSelect(orders1[i], SELECT_BY_TICKET, MODE_TRADES) == false || OrderType() <= OP_SELL)
      {
         if (OrderSelect(orders2[i], SELECT_BY_TICKET, MODE_TRADES)) {
            if (DeleteOrder(orders2[i],clrWhite))
            {
               dbremove = true;
            }
         }
         else {
            dbremove = true;
         }
         
         if (dbremove == true)
         {
            ArrayStripKey(orders1, i);
            ArrayStripKey(orders2, i);
         }
      }
   }
   
   size = ArraySize(orders2);
   dbremove = false;
   for (i=0; i<size; i++)
   {
      if (OrderSelect(orders2[i], SELECT_BY_TICKET, MODE_TRADES) == false || OrderType() <= OP_SELL)
      {
         if (OrderSelect(orders1[i], SELECT_BY_TICKET, MODE_TRADES)) {
            if (DeleteOrder(orders1[i],clrWhite))
            {
               dbremove = true;
            }
         }
         else {
            dbremove = true;
         }
         
         if (dbremove == true)
         {
            ArrayStripKey(orders1, i);
            ArrayStripKey(orders2, i);
         }
      }
   }
   
   return true;
}
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);
}
int OrderCreate(
   string symbol="",
   int    type=OP_BUY,
   double lots=0,
   double op=0,
   double sll=0, // SL level
   double tpl=0, // TO level
   double slp=0, // SL adjust in points
   double tpp=0, // TP adjust in points
   double slippage=0,
   int    magic=0,
   string comment="",
   color  arrowcolor=CLR_NONE,
   datetime expiration=0,
   bool oco = false
   )
{
   int time0=GetTickCount();
   
   int ticket=-1;
   int bs=1;
   if (
         type==OP_SELL
      || type==OP_SELLSTOP
      || type==OP_SELLLIMIT
      ) {bs=-1;} // Positive when Buy, negative when Sell
   
   if (symbol=="") {symbol=Symbol();}

   lots=AlignLots(lots);
   
   int digits = 0;
   double ask=0, bid=0, point=0, ticksize=0;
   double sl=0, tp=0;

   //-- attempt to send trade/order -------------------------------------
   while(!IsStopped())
   {
      //Print(sll+" "+tpl+" "+slp+" "+tpp);
      WaitTradeContextIfBusy();
      
      static bool not_allowed_message = false;
      if (!MQLInfoInteger(MQL_TESTER) && !MarketInfo(symbol, MODE_TRADEALLOWED)) {
         if (not_allowed_message == false) {
            Print("Market ("+symbol+") is closed");
         }
         not_allowed_message = true;
         return(false);
      }
      not_allowed_message = false;
      
      digits     = MarketInfo(symbol,MODE_DIGITS);
      ask     = MarketInfo(symbol,MODE_ASK);
      bid     = MarketInfo(symbol,MODE_BID);
      point   = MarketInfo(symbol,MODE_POINT);
      ticksize= MarketInfo(symbol, MODE_TICKSIZE);
      
      //- not enough money check: fix maximum possible lot by margin required, or quit
      if (type==OP_BUY || type==OP_SELL)
      {
         double LotStep          = MarketInfo(symbol,MODE_LOTSTEP);
         double MinLots          = MarketInfo(symbol,MODE_MINLOT);
         double margin_required  = MarketInfo(symbol,MODE_MARGINREQUIRED);
         static bool not_enough_message = false;
         
         if (margin_required != 0)
         {
            double max_size_by_margin = AccountFreeMargin()/margin_required;
         
            if (lots > max_size_by_margin) {
               double size_old = lots;
               lots = max_size_by_margin;
               if (lots<MinLots)
               {
                  if (not_enough_message==false) {
                     Print("Not enough money to trade :( The robot is still working, waiting for some funds to appear...");
                  }
                  not_enough_message = true;
                  return(false);
               }
               else
               {
                  lots = MathFloor(lots/LotStep)*LotStep;
                  Print("Not enough money to trade "+DoubleToString(size_old, 2)+", the volume to trade will be the maximum possible of "+DoubleToString(lots, 2));
               }
            }
         }
         not_enough_message = false;
      }
      
      //- expiration for trades
      if (type==OP_BUY || type==OP_SELL)
      {
         if (expiration > 0)
         {
            //- convert UNIX to seconds
            if (expiration > TimeCurrent()-100) {
               expiration = expiration - TimeCurrent();
            }
            
            //- bo broker?
            if (StringLen(symbol)>6 && StringSubstr(symbol, StringLen(symbol)-2=="bo")) {
               comment = "BO exp:"+expiration;
            }
            else {
               string expiration_str   = "[exp:"+IntegerToString(expiration)+"]";
               int expiration_len      = StringLen(expiration_str);
               int comment_len         = StringLen(comment);
               if (comment_len > (27-expiration_len))
               {
                  comment = StringSubstr(comment, 0, (27-expiration_len));
               }
               comment = comment + expiration_str;
            }
         }
      }

      if (type==OP_BUY || type==OP_SELL)
      {
         op=ask;
         if (bs<0) {
           op=bid;
         }
      }
      
      op    = NormalizeDouble(op, digits);
      sll   = NormalizeDouble(sll,digits);
      tpl   = NormalizeDouble(tpl,digits);
      if (op<0 || op>=EMPTY_VALUE)  {break;}
      if (sll<0 || slp<0 || tpl<0 || tpp<0) {break;}

      //-- SL and TP ----------------------------------------------------
      double vsl=0, vtp=0;
      
      sl=AlignStopLoss(symbol, type, op, 0, NormalizeDouble(sll,digits), slp);
      if (sl<0) {break;}
      tp=AlignTakeProfit(symbol, type, op, 0, NormalizeDouble(tpl,digits), tpp);
      if (tp<0) {break;}
      
      if (USE_VIRTUAL_STOPS)
      {
         //-- virtual SL and TP --------------------------------------------
         vsl=sl;
         vtp=tp;
         sl=0; tp=0;
         
         double askbid=ask;
         if (bs<0) {askbid=bid;}
         
         if (vsl>0 || USE_EMERGENCY_STOPS=="always") {
            if (EMERGENCY_STOPS_REL>0 || EMERGENCY_STOPS_ADD>0)
            {
               sl=vsl-EMERGENCY_STOPS_REL*MathAbs(askbid-vsl)*bs;
               if (sl<=0) {sl=askbid;}
               sl=sl-toDigits(EMERGENCY_STOPS_ADD,symbol)*bs;
            }
         }
         if (vtp>0 || USE_EMERGENCY_STOPS=="always") {
            if (EMERGENCY_STOPS_REL>0 || EMERGENCY_STOPS_ADD>0)
            {
               tp=vtp+EMERGENCY_STOPS_REL*MathAbs(vtp-askbid)*bs;
               if (tp<=0) {tp=askbid;}
               tp=tp+toDigits(EMERGENCY_STOPS_ADD,symbol)*bs;
            }
         }
         vsl=NormalizeDouble(vsl,digits);
         vtp=NormalizeDouble(vtp,digits);
      }
      
      sl=NormalizeDouble(sl,digits);
      tp=NormalizeDouble(tp,digits);

      //-- fix expiration for pending orders ----------------------------
      if (expiration>0 && type>OP_SELL) {
         if ((expiration-TimeCurrent())<(11*60)) {
            Print("Expiration time cannot be less than 11 minutes, so it was automatically modified to 11 minutes.");
            expiration=TimeCurrent()+(11*60);
         }
      }
      
      //-- fix prices by ticksize
      op = MathRound(op/ticksize)*ticksize;
      sl = MathRound(sl/ticksize)*ticksize;
      tp = MathRound(tp/ticksize)*ticksize;

      //-- send ---------------------------------------------------------
      ResetLastError();
      ticket = OrderSend(symbol,type,lots,op,slippage*PipValue(symbol),sl,tp,comment,magic,expiration,arrowcolor);

      //-- error check --------------------------------------------------
      string msg_prefix="New trade error";
      if (type>OP_SELL) {msg_prefix="New order error";}
      int erraction=CheckForTradingError(GetLastError(), msg_prefix);
      switch(erraction)
      {
         case 0: break;    // no error
         case 1: continue; // overcomable error
         case 2: break;    // fatal error
      }
      
      //-- finish work --------------------------------------------------
      if (ticket>0) {
         if (USE_VIRTUAL_STOPS) {
            VirtualStopsDriver("set", ticket, vsl, vtp, toPips(MathAbs(op-vsl), symbol), toPips(MathAbs(vtp-op), symbol));
         }
         
         //-- show some info
         double slip=0;
         if (OrderSelect(ticket,SELECT_BY_TICKET)) {
            if (!IsTesting() && !IsVisualMode() &&!IsOptimization()) {
               slip=OrderOpenPrice()-op;
               Print(StringConcatenate(
                  "Operation details: Speed ",
                  (GetTickCount()-time0),
                  " ms | Slippage ",
                  DoubleToStr(toPips(slip, symbol),1),
                  " pips"
               ));
            }
         }
         
         //-- fix stops in case of slippage
         if (!IsTesting() && !IsVisualMode() &&!IsOptimization())
         {
            slip = NormalizeDouble(OrderOpenPrice(), digits) - NormalizeDouble(op, digits);
            if (slip != 0 && (OrderStopLoss()!=0 || OrderTakeProfit()!=0))
            {
               Print("Correcting stops because of slippage...");
               sl = OrderStopLoss();
               tp = OrderTakeProfit();
               if (sl != 0 || tp != 0)
               {
                  if (sl != 0) {sl = NormalizeDouble(OrderStopLoss()+slip, digits);}
                  if (tp != 0) {tp = NormalizeDouble(OrderTakeProfit()+slip, digits);}
                  ModifyOrder(ticket, OrderOpenPrice(), sl, tp, 0, 0, 0, CLR_NONE, false);
               }
            }
         }
         
         RegisterEvent("trade");
         break;
      }
      
      break;
   }
   
   if (oco == true && ticket > 0)
   {
      if (USE_VIRTUAL_STOPS) {
         sl = vsl;
         tp = vtp;
      }
      
      sl = NormalizeDouble(MathAbs(op-sl), digits);
      tp = NormalizeDouble(MathAbs(op-tp), digits);
      
      int typeoco = type;
      if (typeoco == OP_BUYSTOP) {
         typeoco = OP_SELLSTOP;
         op = bid - MathAbs(op-ask);
      }
      else if (typeoco == OP_BUYLIMIT) {
         typeoco = OP_SELLLIMIT;
         op = bid + MathAbs(op-ask);
      }
      else if (typeoco == OP_SELLSTOP) {
         typeoco = OP_BUYSTOP;
         op = ask + MathAbs(op-bid);
      }
      else if (typeoco == OP_SELLLIMIT) {
         typeoco = OP_BUYLIMIT;
         op = ask - MathAbs(op-bid);
      }
      
      if (typeoco == OP_BUYSTOP || typeoco == OP_BUYLIMIT)
      {
         sl = op - sl;
         tp = op + tp;
         arrowcolor = clrBlue;
      }
      else {
         sl = op + sl;
         tp = op - tp;
         arrowcolor = clrRed;
      }
         
      comment = "[oco:"+(string)ticket+"]";
      
      OrderCreate(symbol,typeoco,lots,op,sl,tp,0,0,slippage,magic,comment,arrowcolor,expiration,false);
   }
   
   return(ticket);
}
bool OrderModified(double id=-1, string action="set")
{
   static double memory[];
   
   if (id==-1) {
      id=OrderTicket();
      action="get";
   }
   else if (id>-1 && action!="clear") {
      action="set";
   }
   
   bool modified_status=InArray(memory,id);
   
   if (action=="set") {
   //- Set Trade ID
      ArrayValue(memory,id);
      return(true);
   }
   else if (action=="clear") {
   //- Unset Trade ID
      ArrayStrip(memory,id);
      return(true);
   }
   else if (action=="get") {
   //- Get State
      return(modified_status);
   }
   
   Print("Error: The second parameter of the function \"OrderModified\" should be \"set\", \"get\" or \"clear\"");
   return (false);
}
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;
}
int SellNow(
   string symbol,
   double lots,
   double sll,
   double tpl,
   double slp,
   double tpp,
   double slippage=0,
   int magic=0,
   string comment="",
   color arrowcolor=CLR_NONE,
   int expiration = 0
   )
{
   int ticket=OrderCreate(
      symbol,
      OP_SELL,
      lots,
      0,
      sll,
      tpl,
      slp,
      tpp,
      slippage,
      magic,
      comment,
      arrowcolor,
      expiration
      );
   return(ticket);
}
void SetLastIndicatorData(double value=0, string symbol="", int timeframe=0, int shift=0)
{
   LastIndicatorValue(true,value);
   LastIndicatorSymbol(true,symbol);
   LastIndicatorTimeframe(true,timeframe);
   LastIndicatorShift(true,shift);
   IndicatorMoreShift(true,0); // reset
   return;
}
string SetSymbol(string symbol="")
{
	if (symbol=="") {symbol=Symbol();}
   GetSymbol(symbol); return(symbol);
}
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++;    
   }
}

void StringExplode(string delimiter, string explode, int &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] = 0;     
      if (ilEnd == -1){
         if (ilBegin+1 != StringLen(sExplode)){
            sReturn[ilElement] = StrToInteger(StringSubstr(sExplode, ilBegin+1, StringLen(sExplode)));
         }
      } else { 
         if (ilBegin+1 != ilEnd){
            sReturn[ilElement] = StrToInteger(StringSubstr(sExplode, ilBegin+1, ilEnd-ilBegin-1));
         }
      }      
      ilBegin = StringFind(sExplode, sDelimiter,ilEnd);  
      ilElement++;    
   }
}
string StringImplode(string sDelimiter, string &sImplode[]){
   string retval = "";
   int size = ArraySize(sImplode);
   for (int i = 0; i < size; i++) {
      retval = StringConcatenate(retval, sImplode[i], sDelimiter);
   }
   return(StringSubstr(retval, 0, (StringLen(retval) - StringLen(sDelimiter))));
}
string StringImplode(string sDelimiter, int &sImplode[]){
   string retval = "";
   int size = ArraySize(sImplode);
   for (int i = 0; i < size; i++) {
      retval = StringConcatenate(retval, (string)sImplode[i], sDelimiter);
   }
   return(StringSubstr(retval, 0, (StringLen(retval) - StringLen(sDelimiter))));
}
string StringImplode(string sDelimiter, double &sImplode[]){
   string retval = "";
   int size = ArraySize(sImplode);
   
   for (int i = 0; i < size; i++) {
      retval = StringConcatenate(retval, (string)sImplode[i], sDelimiter);
   }
   return(StringSubstr(retval, 0, (StringLen(retval) - StringLen(sDelimiter))));
}
string StringTrim(string text)
{
   static string t; t = text;
   t = StringTrimRight(t);
   t = StringTrimLeft(t);
	return(t);
}
double SymbolAsk(string symbol="")
{
   if (symbol=="") {symbol=GetSymbol();}
   return(MarketInfo(symbol,MODE_ASK));
}
double SymbolBid(string symbol="")
{
   if (symbol=="") {symbol=GetSymbol();}
   return(MarketInfo(symbol,MODE_BID));
}
int SymbolDigits(string symbol="")
{
   if (symbol=="") {symbol=GetSymbol();}
   return(MarketInfo(symbol,MODE_DIGITS));
}
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);
}
int TicksPerSecond(bool get_max = false, bool set = false)
{
   static datetime time0 = 0;
   datetime time1 = TimeLocal();
   static int ticks, tps, tpsmax;
   
   if (set == true)
   {
      if (time1 > time0)
      {
         if (time1-time0 > 1)
         {
            tps = 0;
         }
         else
         {
            tps = ticks;
         }
         time0 = time1;
         ticks = 0;
      }
      
      ticks++;
      
      if (tps > tpsmax) {tpsmax = tps;}
   }
   
   if (get_max)
   {
      return tpsmax;
   }
   
   return tps;
}
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);
}
datetime TimeFromComponents(bool local_time=false, int y=0, int m=0, int d=0, int h=0, int i=0, int s=0)
{
   MqlDateTime tm;
   if (local_time) {TimeLocal(tm);} else {TimeCurrent(tm);}

   if (y>0) {
      if (y<100) {y=2000+y;}
      tm.year = y;
   }
   if (m>0) {tm.mon = m;}
   if (d>0) {tm.day = d;}

   tm.hour  = h;
   tm.min   = i;
   tm.sec   = s;
   
   return StructToTime(tm);
}
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());
   e_attrOpenTime(true,attrOpenTime());
   e_attrCloseTime(true,attrCloseTime());
   e_attrSwap(true,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 WindowFindVisible(long chart_id, string term)
{
   //-- the search term can be chart name, such as Force(13), or subwindow index
   if (term == "" || term == "0") {return 0;}
   
   int subwindow = (int)StringToInteger(term);
  
   if (subwindow == 0 && StringLen(term) > 1)
   {
      subwindow = ChartWindowFind(chart_id, term);
   }
   
   if (subwindow > 0 && !ChartGetInteger(chart_id, CHART_WINDOW_IS_VISIBLE, subwindow))
   {
      return -1;  
   }
   
   return subwindow;
}
double attrClosePrice(string sel="")
{
   return(OrderClosePrice());
}
datetime attrCloseTime(string sel="")
{
   return(OrderCloseTime());
}
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());
}
// The lots closed when partially closing a trade
double attrLotsClosed(double lots=-1)
{
	static double mem=0;
   if (lots>=0) {mem=lots;}
   return(mem);
}
double attrLotsInitial()
{
   int ticket=OrderTicket();
   double retval=OrderLots();
   // When partially closing a trade, OrderLots() is modified to the
   // value of remaining lots after the partial close,
   // so, to get the whole value we need to sum all lots (when
   // partially closed multiple times)
   double second_lots=OrderLots();

   int T = OrderType();
   if (T!=OP_BUY && T!=OP_SELL) {return(0);}
   
   int M = OrderMagicNumber();
   string S = OrderSymbol();
   double OP = OrderOpenPrice();
   double OT = OrderOpenTime();
   double SL = OrderStopLoss();
   double TP = OrderTakeProfit();
   double L = OrderLots();
   
   int digits = MarketInfo(S,MODE_DIGITS);       

   for (int i=OrdersHistoryTotal()-1; i>=0; i--) {
      if (OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) {
         // Searching for the match starting from newest trade
         // modify "retval" when match found, but end the loop
         // when the current trade is older than the one we search
         if (
            (OrderSymbol()==S)
            && (OrderMagicNumber()==M)
            && (NormalizeDouble(OrderOpenPrice(),digits)==NormalizeDouble(OP,digits))
            //&& (OrderLots()<L)
            && (OrderOpenTime()==OT)
            )
         {
            //Print("PartialExit Match from "+ticket+" found by ticket: "+OrderTicket());
            //Print("LOTS: "+OrderLots()+"+"+second_lots);
            retval=OrderLots()+second_lots;
            second_lots=OrderLots()+second_lots;
         }
         else if (OrderOpenTime()<OT) {
            // this trade is too old, break the loop here
            break;
         }
      }
   }
   // Reload the trade that we are working with
   OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES);
   return(retval); 
}
int attrMagicNumber(string sel="")
{
   return(OrderMagicNumber());
}
double attrOpenPrice(string sel="")
{
   return(OrderOpenPrice());
}
datetime attrOpenTime(string sel="")
{
   return(OrderOpenTime());
}
double attrProfit(string sel="")
{
   return(OrderProfit());
}
double attrStopLoss()
{
   if (USE_VIRTUAL_STOPS) {return(VirtualStopsDriver("get sl",OrderTicket()));}
   return(OrderStopLoss());
}
double attrSwap(string sel="")
{
   return(OrderSwap());
}
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);
}
double attrType(string sel="")
{
   return(OrderType());
}
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]);}
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]);}
datetime e_attrCloseTime(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]);}
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]);}
int iCandleID(string SYMBOL, int TIMEFRAME, datetime time_stamp)
{
   bool TimeStampPrevDayShift = true;
   int CandleID = 0;
   //== calculate candle ID
   //-- get the time resolution of the desired period, in minutes
   int mins_tf = TIMEFRAME;
   int mins_tf0 = 0;
   if (TIMEFRAME == PERIOD_CURRENT)
   {
      //-- calculate the current period minutes
      //-- we need to calculate the difference in time between 2 candles
      // but because we have holidays, we will compare 2 neighbour candles until we get the same time difference
      int i=0;   
      while(true)
      {
         mins_tf = (int)(iTime(SYMBOL, TIMEFRAME, i) - iTime(SYMBOL, TIMEFRAME, i+1));
   
         if (mins_tf0 == mins_tf) {break;}
         mins_tf0 = mins_tf;
         i++;
      }
      mins_tf = mins_tf / 60;
   }
   
   //-- get the difference between now and the time we want, in minutes
   //int time_stamp = StrToTime(TimeStamp);
   int days_adjust = 0;
   if (TimeStampPrevDayShift)
   {
      //-- automatically shift to the previous day
      if (time_stamp > TimeCurrent())
      {
         time_stamp = time_stamp - 86400;
      }
      //-- also shift weekdays
      while (true)
      {
         int dow = TimeDayOfWeek(time_stamp);
         
         if (dow > 0 && dow < 6) {break;}
         time_stamp = time_stamp - 86400;
         days_adjust++;
      }
   }
   
   int mins_diff = (int)(TimeCurrent() - time_stamp);
   mins_diff = mins_diff - days_adjust*86400;
   mins_diff = mins_diff / 60;
   
   //-- the difference is negative => quit here
   if (mins_diff < 0) {return (int)EMPTY_VALUE;}
   
   //-- now calculate the candle ID, it is relative to the current time
   if (mins_diff > 0) {
      CandleID = (int)MathCeil((double)mins_diff/(double)mins_tf);
   }
   //Print(TimeToStr(TimeCurrent())+" "+TimeToStr(time_stamp) +" ::: " + mins_tf + " " + days_adjust + " " + (days_adjust*1440/mins_tf) + " " + CandleID);
   
   
   //-- now, after all the shifting and in case of missing candles, the calculated candle id can be few candles early
   // so we will search for the right candle
   while(true)
   {
      if (iTime(SYMBOL, TIMEFRAME, CandleID) >= time_stamp) {break;}
      
      CandleID--;
   }
   
   return CandleID;
   
   /*
   // this method does the same, but it is slower
   
   if (0)
   {
      CandleID = 0;
      datetime t = StrToTime(TimeStamp);
      datetime now = TimeCurrent();
      datetime ctime;
      while(true)
      {
         ctime = iTime(SYMBOL, TIMEFRAME, CandleID);
         //
         if (ctime < t)
         {
            //-- if the time is still in the future, we will shift to a previous day
            if (t > now)
            {
               if (TimeStampPrevDayShift)
               {
                  //-- shift to the last day that is not sat/sun
                  while(true)
                  {
                     t = t - 86400;
                     int dow = TimeDayOfWeek(t);
                     if (dow > 0 && dow < 6) {break;}
                  }
                  continue;
               }
               return EMPTY_VALUE;
            }
            break;
         }
         CandleID++;
      }
   }
   
   */
}
double toDigits(double pips,string symbol="")
{
	if (symbol=="") {symbol=GetSymbol();}
   return(
      NormalizeDouble(
         pips*PipValue(symbol)*MarketInfo(symbol,MODE_POINT),
         MarketInfo(symbol,MODE_DIGITS)
      )
   );
}
double toPips(double digits,string symbol="")
{
   if (symbol=="") {symbol=GetSymbol();}
   return(digits/(PipValue(symbol)*MarketInfo(symbol,MODE_POINT)));
}
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:eNrtXOtz4sgR/1eIP6TuKrsbvXnsJ8D47JSwHWBvs/lCyWjAEwuNIgl7uSv/7+l56YWEBYeXs0PV1pqa7pnu+U13T89LTqfV+T2C/84iFMfYX0Rnn52OptFCVeucBSH5D5rFU99ZorPPUUc3O2eXeHGPorhxEyB/apOn5Pd4YNvTR/WTolDWbPV4HbDqVucMfQ9QGEuGGXGR5/iLlbNgDEbnbPhP22BktXPmOjGazkIEf84+445qWIaqamrTyNKXxMXzdUo326Yu6EtngWfTKHa4RGjdbFmKbP3OI7OHiNZnsqGEk5qds0XoBPdTEmLkx06MiS/rTEgwIT0Sx2TJiqBHzizGj6AmAVbso5CWA0yT0OHtalDtEUf4zkNTD9+FTrieLkKyCgQi0TqKEW+tnXIy5ar49M5ZjJconEYIxLoR7bylCBUDgv14Gq48xAZT7/yOOwodVTqoAME85LqDjgqMlcp0hAaJgAgKoewZ4Cyp1OSVitUsUcwraiUVW7LilprPHPxVhKaPOIxXjgdjR4JIVPBJCmeGOqVQkFVMQVAEirQJBAAtkD9blzRCeQr0aYi8nBmUsDium2OBH+gRTCQ1IoOOzOwhaYBTZ+sZDCkYPiYuM1RKBtYIL1cetWFaJ8o2TXuZp06XTviAYoHZ4Mvoy/gcMGND8oR9lzxlfDcpU2mZqggn52VX52IkE5ao06bjEdzM5xFiQOoqg1LpnHloHqflTd3k3Dlzh65c+TgWEGNXmNdgGcRr0ToGFFYRc5s7NkygjosjB2zdlUV08AMnhFgToxD4CQldhgqoIZqMZo4nQ4lPwqXjifaFZ/G+pbKfM/1WjUowcjybaKimWYqGqSs10VBBpf49xKHz0HnqrSB++McAplSNHEZmDYzMXTCyalvMm8HIqoGRtQtGzfeHUbMGRs1dMGq9P4xaNTBqlWJklUfn9rvDSKsRj7TSeKTp5XZkWLVjtp5RboK+x0dBaFOJHD41YpFm7WJDZrsMn1xCmzUixIqn7P9r9HQsI9pQIwdSjWCkNXcxovJJrRyk7ADawHp0K+JK5ACqEYm0ikhUBVCFFTEtcgBpoBtixdMhgcS970G6e3NHF47HgGqrOlnQdO1l0ChPiVWpFaBZtUEDCbdOFN34s6PYU058DpQaObZu7GJJLc1895ZUI4jrpUFca/5h0Og2zJBtodBNHOQeJTxt6JCDp0b41pu72JSqqO8/PNWI6XprF6NSFaM2anROtgkJkNv3SIRuBf0YqcGGGlmUjBr5pWHuZFua8u5ty6gRsIydApbK58T3ZVs14paxW9zS2+/ftmrELWO3uGUo9W1LhVI6nEecDIsq5NBp10CnXYqOUrGjWxquQMNz9Ab2dE3lZTxMpRSPivWv1ayPB9u+8JATdj2P23J0tF2Uoho5lNQaKJWeA2itCpRatQMR9HKMPO+aHGVzICudHTAp2YarTkxMWgQRq/SsBHr2ZBfdgRZei50kujSS1fq5nlKuWyoAhuJ582yimRdbOJVI5FZs3iUqUPAoqcFpf/XvouDzCwppqjzz5RZ0i8KeIwd17ngRkok6p38JXHYqy4+8whUS7QP1WhwWw7iMuvRQWHAB6V9CT11Jy76JspaSNsE3usQpYmJJ1DiBMI3FXlzJWIpTx8xuHR39hk+e/iJr9G9Go0F/cnVzndjT87MUfAHmLDrdDTE3KRqQBWmMf5O7O3xMWrxbkSiHsYP8LyV8i9IKfJuSagCE3qJPPBLKkpkX9kO8jMRBMwemBzaPwoSvxdh6nsOPF9uMp09C4Xt00KFr14PR1B5cTKb2zdfBKNVkHIvhyg5nS7QhJLSZhJvQ8ReZ4ewJgTk70HmjyANToI67waBmGJBbJHPlL7HrIr+c9m/W+eK5PNWWGv54dfeVeUY6hFzm0xhRi4gJtwdD2E+kipakA0dasUAvFhhpgThlpRiuUjsDpYlP5vOskga7lODkLKtwuFbp5OZbdPIm
c3K7N1A3vdwoejl1D/UV3JxyjO1GTBq9wd/UQzu6VuHoysnRT45e7ujWVke33qKjU9BHXbYwaah/N2p6u/E6k3pOjZOvn3z9iL7e3Orrzbfv61pNX2++rq9rJ18/+fqRfb211ddbb93Xu55XY60OXdeU1/R1ocZpsX7y9eP5urZ1sa4VFutlV8VSTzeFp1PKsfy8Td2cv6VwM7YNlSfidQYdy94/pna3N7BTg5vgJVI33ZtWf3S8FWLX7yscXBUbzkPioolkg4gi2WnZmKzCWe4BRlsQYmcZyIcKSid9VUKJfcd3PSS2v6XNiRaHyUV5sVmstrOV6K956Cw3Hn0wFrIMiI/8+BvieMsmWgX6EALMfZbBKjCcO+ssudj+JXQ7l4gkSiYSsL+KUfFJQo5lzJ5/5Fj0FO3xPZ7HOaIhkKUE2sHsjjo10oTIepejZqt+ReghR9QzROh3ZUXa6agENC6T9beSPJZPXTbJDzigKrlCcuoi1KF5hLoN8azUjIF5xswimoq/5bbcFEEE31zafbG7jdl0JVWhsHMLu4AQ0VsX72uVmWzR1EXPoLXxt2Hvxs6UUdar4eBi1B0OilZfMUvm53G1/YPmcR3q9nmgadytG/E9Cp0IJCkNJ25cXMxJuFoecn6HkmYar7r+wiuGk3pzb1vUn92ThLF73b+8KZ+kk5m4Keb61Wkefo15eOtemra5l1ZyIzmZiTXQ6CfiN2JK/LkBZP6zQZLj/i2zskWVAKR/oa/yhuLFl0lfC4pXeqagZYMU/OUTkqxg0XeJmadcm9MV4NJbraObkJ5dRQKhO8LnG9pgNwzJUzbXPEcouMX+Q9WQ6nsN6aFGcOsOidaszqTkdenNTIpSjpVJmTSTmtyqW7OoS/vqenDKok5Z1P9DFqVZ4qkrD71o6sRxSK8vsQrlZs39ciMFgJY+WgGm73VFEBHeo/2pvYca4Ml9Tu7zsvtof5pFSGKzr7sKKaTl9PTAFM1D+YhbaGayFVMqEGw0jytyZKCO8OI+fmGTjH1jwgtt6N0vIeJps9xiW3sJauPJN3swPe+OL89vJvAvZfuKXZF2iY7umN5n+3XK7ktyw1aSWJflhvkd9ReuNCdZot7iWf6Msv7cYLyNGWVuQClhFeolj2yOgg7Q1O8Ce+CHw/RDD356Bab81tuBMOIPzcwKjPgTswSjwsOwNHOmzk9WPnSh06AcAMUMvdB/VSx4RMUkUVSLGhrbRlE33t4oZq81HWoYty5k9cJCtuRVVrqKbUlig32XpEHmfBkb1cJDZabEwhENKNF4RoKNpWxK3ljRAmW8Xt4RL6nIvk5DS6qmjReWtJqQlZl9sxPLCHkO/cbOhIhgSFfrQZJaAiss5Mf25HaZrsnn+Dtys2QAyiaR/AzMR1U6RYYGa8MZ8qUVmkmyN8/V35i9oScwhHjGQuwUd/vlkzcLvLvMqdCL8eXVxaTmPEvnH1B04jyg25DMcTb51JQCrbSrBu9qtoWNzqoy5Wb/b9kQBO1/lSypiC3qwy8bFhHeLvsaZnEyU4qTmVKczJTiZJYUmAef3fjLxcq42Hx7cXHjFtihkNqaB+ibJ+slD8DS+KjTrI+q+BMYS4wdz1v/XAuSJDLSNn8lnsSDSgy4y3zEPo4zm9GC0yZxlH5Ay5T+JKh5d+OHh9C7sYeDQHz6DJoy6u3vHQJv/u6xCm/DfOuWqR0OKWsrUta7skxTOb5lbo2ZxhuPmexqy6GQ2nobySjEzM2Hjfm1AVNvhyyy9WdIIukzMPl7Wxa5t0UfJudQX8w5lMNZRXvbapG/DX2NF2z8JWaVNZrK5t24zYeTqUUadBw8yCiFc0Z1juakX47pBz+jr5ivLjTqfdJAKLnPnyxmd/GK20aA9GB4O/k2/bVrf5HHOGMSJod40MXfPjrpAd/3TC+yJv6AgyJl3xM65fVO6Pj70Mqxy796zL/nzA2ZfGtXb0ZT8xGkGCJKQwD8hUlrtUTJ/Me+MYrQ0gkX2B/h
6CHPN04v+ymfVFkjpckauSUKJ0sSvSf4KdnY5rTMtJleGaZxlJN79OutGZ7kwIF+tDar2GHWV5nObVlggXYXdFU8ol+0/QK5gsQm+egrd8yUCVyQmwxNWhVJXy6HiyueasjcIqNAizMMV16MA29948tVN/RMk2vRPEe6XJV2Tzc2KU/XdamIXCPJKUSOIddGTtURilBc0kIzR67SQdU1q7qzumQZwco1jDZvdLA2LvAdqWxD0yjLueOh5R0K4xeATfgqBGpMI9u5I6vZPQpRdXNWntHGUSwNUP2gfdA/GB/MD1aKdcpa1Vcmeoz+23MiVCJQFeR0KKC2DqKsXO3SodAEsUq0JR3vSwDJsI2Xud0PWl3u3yRxA8rcNSRseMZ2HYp8tziICt7dzFC5a09uCywg0PW2bBXt7d1Kne0TN3gF0Wo90e6hRfMPQ9eQTs/2kh2rYdkOYI5DDmwa8Ns5Mh/ZsV3oPjUX7/A7Y4mFb+kgFR0cXnS9saXC3cMLrzu64HOD70Em6/pl0hd5BZTLY95Mmg+lyQFvFlzayua6gGZFQDns1QLl4Bdz1NPNgu03C7QffrMgGZUff7UgOVMWOXzZyhagHK4ByKVMQOli5B4WMHyJLzVPF780dRcuNhIfHdpr7av+8LWv0BTQ82GdhYnPrxfJc+6Zkiyv2KSAPHnN83xw0f1iT+TeQ+KohcUy0GA9ueAul1vQPnMB6v4CzGoBdGdRCND2FsAP0MsF6FoiwNhbAD/brRCQ9sDcX0Bzi4BWIsDafwy2CDBSAc39x8CqFkAvvwoBrb0FqJtjkP1gkWi/vX/75kvt011tdX8/U61aAvb3M7VZS8D+fqa2agnQ9zeiemPwBxxZ2xLr1CQZQ98h+/HTC5yFLSS5i4UqtlI2F0iqrKGKXEikiNxqkVaVwItbdRD1o9jx40huSbLSRyfE9AZWphRadkLkJCXP/wMs+grq
:fxdreema>*/