divergence alert2

0 Views
0 Downloads
0 Favorites
divergence alert2


#property copyright   "metatrooper.store"

#property link        "metatrooper.store"

#property description ""

#property version     "1.0"

#property strict



/************************************************************************************************************************/

// +------------------------------------------------------------------------------------------------------------------+ //

// |                       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 "mt5-9724"

//--

// Point Format Rules

#define POINT_FORMAT_RULES "0.001=0.01,0.00001=0.0001,0.000001=0.0001" // this is deserialized in a special function later

#define ENABLE_SPREAD_METER true

#define ENABLE_STATUS true

#define ENABLE_TEST_INDICATORS true

//--

// Events On/Off

#define ENABLE_EVENT_TICK 1 // enable "Tick" event

#define ENABLE_EVENT_TRADE 0 // enable "Trade" event

#define ENABLE_EVENT_TIMER 0 // enable "Timer" event

//--

// Virtual Stops

#define VIRTUAL_STOPS_ENABLED 0 // enable virtual stops

#define VIRTUAL_STOPS_TIMEOUT 0 // virtual stops timeout

#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)

//--

// Settings for events

#define ON_TIMER_PERIOD 60 // Timer event period (in seconds)



//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_FIRSTLEVEL 806

#define OBJPROP_TIME1 807

#define OBJPROP_TIME2 808

#define OBJPROP_TIME3 809

#define OBJPROP_PRICE1 810

#define OBJPROP_PRICE2 811

#define OBJPROP_PRICE3 812

#define OBJPROP_BARSHIFT1 813

#define OBJPROP_BARSHIFT2 814

#define OBJPROP_BARSHIFT3 815

#define SEL_CURRENT 0

#define SEL_INITIAL 1



//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//

// Enumerations, Imports, Constants, Variables //

//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//













//--

// Constants (Input Parameters)

input double multi = 4.0;

input int MagicStart = 9724; // Magic Number, kind of...

class c

{

		public:

	static double multi;

	static int MagicStart;

};

double c::multi;

int c::MagicStart;





//--

// Variables (Global Variables)

class v

{

		public:

};







//--

// Externs (Global Variables)

input int inp3_fastEMA = 12;

input int inp3_slowEMA = 26;

input int inp3_signalSMA = 9;

input double inp3_macdThreshold = 0.0003;

input ENUM_TIMEFRAMES inp3_Period = NULL;

input int inp4_fastEMA = 12;

input int inp4_slowEMA = 26;

input int inp4_signalSMA = 9;

input double inp4_macdThreshold = 0.0003;

input ENUM_TIMEFRAMES inp4_Period = NULL;

input int inp5_Lo_Kperiod = 50;

input int inp5_Lo_Dperiod = 9;

input int inp5_Lo_Slowing = 20;

input int inp5_Lo_Mode = 0;

input ENUM_TIMEFRAMES inp5_Lo_Period = NULL;

input int inp5_Ro_Kperiod = 50;

input int inp5_Ro_Dperiod = 9;

input int inp5_Ro_Slowing = 20;

input int inp5_Ro_Mode = 1;

input ENUM_TIMEFRAMES inp5_Ro_Period = NULL;

input int inp6_Lo_Kperiod = 50;

input int inp6_Lo_Dperiod = 9;

input int inp6_Lo_Slowing = 20;

input int inp6_Lo_Mode = 0;

input ENUM_TIMEFRAMES inp6_Lo_Period = NULL;

input int inp6_Ro_Kperiod = 50;

input int inp6_Ro_Dperiod = 9;

input int inp6_Ro_Slowing = 20;

input int inp6_Ro_Mode = 1;

input ENUM_TIMEFRAMES inp6_Ro_Period = NULL;

input int inp9_Indicator_Kperiod = 50;

input int inp9_Indicator_Dperiod = 9;

input int inp9_Indicator_Slowing = 20;

input ENUM_TIMEFRAMES inp9_Indicator_Period = NULL;

input int inp9_CandlesShift = 1;

input int inp9_CandlesPeriod = 1;

input int inp9_ExceptionCandles = 0;

input double inp9_UpperLevel = 30.0;

input double inp9_LowerLevel = 0.0;

input int inp10_Indicator_Kperiod = 50;

input int inp10_Indicator_Dperiod = 9;

input int inp10_Indicator_Slowing = 20;

input ENUM_TIMEFRAMES inp10_Indicator_Period = NULL;

input int inp10_CandlesShift = 1;

input int inp10_CandlesPeriod = 1;

input int inp10_ExceptionCandles = 0;

input double inp10_UpperLevel = 100.0;

input double inp10_LowerLevel = 70.0;

input string inp14_AlertTitle = "Your Alert Message here";

input bool inp14_AlsoSendNotification = false;

input string inp15_AlertTitle = "Alert Message";

input bool inp15_AlsoSendNotification = false;

class _externs

{

		public:

	static int inp3_fastEMA;

	static int inp3_slowEMA;

	static int inp3_signalSMA;

	static double inp3_macdThreshold;

	static ENUM_TIMEFRAMES inp3_Period;

	static int inp4_fastEMA;

	static int inp4_slowEMA;

	static int inp4_signalSMA;

	static double inp4_macdThreshold;

	static ENUM_TIMEFRAMES inp4_Period;

	static int inp5_Lo_Kperiod;

	static int inp5_Lo_Dperiod;

	static int inp5_Lo_Slowing;

	static int inp5_Lo_Mode;

	static ENUM_TIMEFRAMES inp5_Lo_Period;

	static int inp5_Ro_Kperiod;

	static int inp5_Ro_Dperiod;

	static int inp5_Ro_Slowing;

	static int inp5_Ro_Mode;

	static ENUM_TIMEFRAMES inp5_Ro_Period;

	static int inp6_Lo_Kperiod;

	static int inp6_Lo_Dperiod;

	static int inp6_Lo_Slowing;

	static int inp6_Lo_Mode;

	static ENUM_TIMEFRAMES inp6_Lo_Period;

	static int inp6_Ro_Kperiod;

	static int inp6_Ro_Dperiod;

	static int inp6_Ro_Slowing;

	static int inp6_Ro_Mode;

	static ENUM_TIMEFRAMES inp6_Ro_Period;

	static int inp9_Indicator_Kperiod;

	static int inp9_Indicator_Dperiod;

	static int inp9_Indicator_Slowing;

	static ENUM_TIMEFRAMES inp9_Indicator_Period;

	static int inp9_CandlesShift;

	static int inp9_CandlesPeriod;

	static int inp9_ExceptionCandles;

	static double inp9_UpperLevel;

	static double inp9_LowerLevel;

	static int inp10_Indicator_Kperiod;

	static int inp10_Indicator_Dperiod;

	static int inp10_Indicator_Slowing;

	static ENUM_TIMEFRAMES inp10_Indicator_Period;

	static int inp10_CandlesShift;

	static int inp10_CandlesPeriod;

	static int inp10_ExceptionCandles;

	static double inp10_UpperLevel;

	static double inp10_LowerLevel;

	static string inp14_AlertTitle;

	static bool inp14_AlsoSendNotification;

	static string inp15_AlertTitle;

	static bool inp15_AlsoSendNotification;

};

int _externs::inp3_fastEMA;

int _externs::inp3_slowEMA;

int _externs::inp3_signalSMA;

double _externs::inp3_macdThreshold;

ENUM_TIMEFRAMES _externs::inp3_Period;

int _externs::inp4_fastEMA;

int _externs::inp4_slowEMA;

int _externs::inp4_signalSMA;

double _externs::inp4_macdThreshold;

ENUM_TIMEFRAMES _externs::inp4_Period;

int _externs::inp5_Lo_Kperiod;

int _externs::inp5_Lo_Dperiod;

int _externs::inp5_Lo_Slowing;

int _externs::inp5_Lo_Mode;

ENUM_TIMEFRAMES _externs::inp5_Lo_Period;

int _externs::inp5_Ro_Kperiod;

int _externs::inp5_Ro_Dperiod;

int _externs::inp5_Ro_Slowing;

int _externs::inp5_Ro_Mode;

ENUM_TIMEFRAMES _externs::inp5_Ro_Period;

int _externs::inp6_Lo_Kperiod;

int _externs::inp6_Lo_Dperiod;

int _externs::inp6_Lo_Slowing;

int _externs::inp6_Lo_Mode;

ENUM_TIMEFRAMES _externs::inp6_Lo_Period;

int _externs::inp6_Ro_Kperiod;

int _externs::inp6_Ro_Dperiod;

int _externs::inp6_Ro_Slowing;

int _externs::inp6_Ro_Mode;

ENUM_TIMEFRAMES _externs::inp6_Ro_Period;

int _externs::inp9_Indicator_Kperiod;

int _externs::inp9_Indicator_Dperiod;

int _externs::inp9_Indicator_Slowing;

ENUM_TIMEFRAMES _externs::inp9_Indicator_Period;

int _externs::inp9_CandlesShift;

int _externs::inp9_CandlesPeriod;

int _externs::inp9_ExceptionCandles;

double _externs::inp9_UpperLevel;

double _externs::inp9_LowerLevel;

int _externs::inp10_Indicator_Kperiod;

int _externs::inp10_Indicator_Dperiod;

int _externs::inp10_Indicator_Slowing;

ENUM_TIMEFRAMES _externs::inp10_Indicator_Period;

int _externs::inp10_CandlesShift;

int _externs::inp10_CandlesPeriod;

int _externs::inp10_ExceptionCandles;

double _externs::inp10_UpperLevel;

double _externs::inp10_LowerLevel;

string _externs::inp14_AlertTitle;

bool _externs::inp14_AlsoSendNotification;

string _externs::inp15_AlertTitle;

bool _externs::inp15_AlsoSendNotification;







//VVVVVVVVVVVVVVVVVVVVVVVVV//

// System global variables //

//^^^^^^^^^^^^^^^^^^^^^^^^^//

//--

// Blocks Lookup Functions

string fxdBlocksLookupTable[];



int FXD_CURRENT_FUNCTION_ID = 0;

double FXD_MILS_INIT_END    = 0;

int FXD_TICKS_FROM_START    = 0;

int FXD_MORE_SHIFT          = 0;

bool FXD_DRAW_SPREAD_INFO   = false;

bool FXD_FIRST_TICK_PASSED  = false;

bool FXD_BREAK              = false;

bool FXD_CONTINUE           = false;

bool USE_VIRTUAL_STOPS = VIRTUAL_STOPS_ENABLED;

string FXD_CURRENT_SYMBOL   = "";

int FXD_BLOCKS_COUNT        = 11;

datetime FXD_TICKSKIP_UNTIL = 0;



int FXD_ICUSTOM_HANDLES_IDS[]; // only used in MQL5

string FXD_ICUSTOM_HANDLES_KEYS[]; // only used in MQL5



//- for use in OnChart() event

struct fxd_onchart

{

	int id;

	long lparam;

	double dparam;

	string sparam;

};

fxd_onchart FXD_ONCHART;



/************************************************************************************************************************/

// +------------------------------------------------------------------------------------------------------------------+ //

// |                                                 EVENT FUNCTIONS                                                  | //

// |                           These are the main functions that controls the whole project                           | //

// +------------------------------------------------------------------------------------------------------------------+ //

/************************************************************************************************************************/



//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//

// This function is executed once when the program starts //

//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//

int OnInit()

{



	// Initiate Constants

	c::multi = multi;

	c::MagicStart = MagicStart;









	// Initiate Externs

	_externs::inp3_fastEMA = inp3_fastEMA;

	_externs::inp3_slowEMA = inp3_slowEMA;

	_externs::inp3_signalSMA = inp3_signalSMA;

	_externs::inp3_macdThreshold = inp3_macdThreshold;

	_externs::inp3_Period = inp3_Period;

	_externs::inp4_fastEMA = inp4_fastEMA;

	_externs::inp4_slowEMA = inp4_slowEMA;

	_externs::inp4_signalSMA = inp4_signalSMA;

	_externs::inp4_macdThreshold = inp4_macdThreshold;

	_externs::inp4_Period = inp4_Period;

	_externs::inp5_Lo_Kperiod = inp5_Lo_Kperiod;

	_externs::inp5_Lo_Dperiod = inp5_Lo_Dperiod;

	_externs::inp5_Lo_Slowing = inp5_Lo_Slowing;

	_externs::inp5_Lo_Mode = inp5_Lo_Mode;

	_externs::inp5_Lo_Period = inp5_Lo_Period;

	_externs::inp5_Ro_Kperiod = inp5_Ro_Kperiod;

	_externs::inp5_Ro_Dperiod = inp5_Ro_Dperiod;

	_externs::inp5_Ro_Slowing = inp5_Ro_Slowing;

	_externs::inp5_Ro_Mode = inp5_Ro_Mode;

	_externs::inp5_Ro_Period = inp5_Ro_Period;

	_externs::inp6_Lo_Kperiod = inp6_Lo_Kperiod;

	_externs::inp6_Lo_Dperiod = inp6_Lo_Dperiod;

	_externs::inp6_Lo_Slowing = inp6_Lo_Slowing;

	_externs::inp6_Lo_Mode = inp6_Lo_Mode;

	_externs::inp6_Lo_Period = inp6_Lo_Period;

	_externs::inp6_Ro_Kperiod = inp6_Ro_Kperiod;

	_externs::inp6_Ro_Dperiod = inp6_Ro_Dperiod;

	_externs::inp6_Ro_Slowing = inp6_Ro_Slowing;

	_externs::inp6_Ro_Mode = inp6_Ro_Mode;

	_externs::inp6_Ro_Period = inp6_Ro_Period;

	_externs::inp9_Indicator_Kperiod = inp9_Indicator_Kperiod;

	_externs::inp9_Indicator_Dperiod = inp9_Indicator_Dperiod;

	_externs::inp9_Indicator_Slowing = inp9_Indicator_Slowing;

	_externs::inp9_Indicator_Period = inp9_Indicator_Period;

	_externs::inp9_CandlesShift = inp9_CandlesShift;

	_externs::inp9_CandlesPeriod = inp9_CandlesPeriod;

	_externs::inp9_ExceptionCandles = inp9_ExceptionCandles;

	_externs::inp9_UpperLevel = inp9_UpperLevel;

	_externs::inp9_LowerLevel = inp9_LowerLevel;

	_externs::inp10_Indicator_Kperiod = inp10_Indicator_Kperiod;

	_externs::inp10_Indicator_Dperiod = inp10_Indicator_Dperiod;

	_externs::inp10_Indicator_Slowing = inp10_Indicator_Slowing;

	_externs::inp10_Indicator_Period = inp10_Indicator_Period;

	_externs::inp10_CandlesShift = inp10_CandlesShift;

	_externs::inp10_CandlesPeriod = inp10_CandlesPeriod;

	_externs::inp10_ExceptionCandles = inp10_ExceptionCandles;

	_externs::inp10_UpperLevel = inp10_UpperLevel;

	_externs::inp10_LowerLevel = inp10_LowerLevel;

	_externs::inp14_AlertTitle = inp14_AlertTitle;

	_externs::inp14_AlsoSendNotification = inp14_AlsoSendNotification;

	_externs::inp15_AlertTitle = inp15_AlertTitle;

	_externs::inp15_AlsoSendNotification = inp15_AlsoSendNotification;







	// do or do not not initilialize on reload

	if (UninitializeReason() != 0)

	{

		if (UninitializeReason() == REASON_CHARTCHANGE)

		{

			// if the symbol is the same, do not reload, otherwise continue below

			if (FXD_CURRENT_SYMBOL == Symbol()) {return INIT_SUCCEEDED;}

		}

		else

		{

			return INIT_SUCCEEDED;

		}

	}

	FXD_CURRENT_SYMBOL = Symbol();



	CurrentSymbol(FXD_CURRENT_SYMBOL); // CurrentSymbol() has internal memory that should be set from here when the symboll is changed

	CurrentTimeframe(PERIOD_CURRENT);











	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();







	//-- disable virtual stops in optimization, because graphical objects does not work

	// http://docs.mql4.com/runtime/testing

	if (MQLInfoInteger(MQL_OPTIMIZATION)) {

		USE_VIRTUAL_STOPS = false;

	}



	//-- set initial local and server time

	TimeAtStart("set");



	//-- set initial balance

	AccountBalanceAtStart();



	//-- draw the initial spread info meter

	if (ENABLE_SPREAD_METER == false) {

		FXD_DRAW_SPREAD_INFO = false;

	}

	else {

		FXD_DRAW_SPREAD_INFO = !(MQLInfoInteger(MQL_TESTER) && !MQLInfoInteger(MQL_VISUAL_MODE));

	}

	if (FXD_DRAW_SPREAD_INFO) DrawSpreadInfo();



	//-- draw initial status

	if (ENABLE_STATUS) DrawStatus("waiting for tick...");



	//-- draw indicators after test

	TesterHideIndicators(!ENABLE_TEST_INDICATORS);



	if (ENABLE_EVENT_TIMER) {

		OnTimerSet(ON_TIMER_PERIOD);

	}





	//-- Initialize blocks classes

	ArrayResize(_blocks_, 11);



	_blocks_[0] = new Block0();

	_blocks_[1] = new Block1();

	_blocks_[2] = new Block2();

	_blocks_[3] = new Block3();

	_blocks_[4] = new Block4();

	_blocks_[5] = new Block5();

	_blocks_[6] = new Block6();

	_blocks_[7] = new Block7();

	_blocks_[8] = new Block8();

	_blocks_[9] = new Block9();

	_blocks_[10] = new Block10();



	// fill the lookup table

	ArrayResize(fxdBlocksLookupTable, ArraySize(_blocks_));

	for (int i=0; i<ArraySize(_blocks_); i++)

	{

		fxdBlocksLookupTable[i] = _blocks_[i].__block_user_number;

	}



	// fill the list of inbound blocks for each BlockCalls instance

	for (int i=0; i<ArraySize(_blocks_); i++)

	{

		_blocks_[i].__announceThisBlock();

	}



	// List of initially disabled blocks

	int disabled_blocks_list[] = {};

	for (int l = 0; l < ArraySize(disabled_blocks_list); l++) {

		_blocks_[disabled_blocks_list[l]].__disabled = true;

	}







	FXD_MILS_INIT_END     = (double)GetTickCount();

	FXD_FIRST_TICK_PASSED = false; // reset is needed when changing inputs



	return(INIT_SUCCEEDED);

}



//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//

// This function is executed on every incoming tick //

//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//

void OnTick()

{

	FXD_TICKS_FROM_START++;



	if (ENABLE_STATUS && FXD_TICKS_FROM_START == 1) DrawStatus("working");



	//-- special system actions

	if (FXD_DRAW_SPREAD_INFO) DrawSpreadInfo();

	TicksData(""); // Collect ticks (if needed)

	TicksPerSecond(false, true); // Collect ticks per second

	if (USE_VIRTUAL_STOPS) {VirtualStopsDriver();}



	if (false) ExpirationWorker * expirationDummy = new ExpirationWorker();

	expirationWorker.Run();



	OCODriver(); // Check and close OCO orders



	// skip ticks

	if (TimeLocal() < FXD_TICKSKIP_UNTIL) {return;}



	//-- run blocks

	int blocks_to_run[] = {0};

	for (int i=0; i<ArraySize(blocks_to_run); i++) {

		_blocks_[blocks_to_run[i]].run();

	}





	return;

}



//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//

// This function is executed on trade events - open, close, modify //

//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//

void OnTrade()

{

	// This is needed so that the OnTradeEventDetector class is added into the code

	if (false) OnTradeEventDetector * dummy = new OnTradeEventDetector();



}





//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//

// This function is executed on a period basis //

//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//

void OnTimer()

{



}





//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

)

{

	//-- write parameter to the system global variables

	FXD_ONCHART.id     = id;

	FXD_ONCHART.lparam = lparam;

	FXD_ONCHART.dparam = dparam;

	FXD_ONCHART.sparam = sparam;





	return;

}



//VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//

// This function is executed once when the program ends //

//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^//

void OnDeinit(const int reason)

{

	int reson = UninitializeReason();

	if (reson == REASON_CHARTCHANGE || reson == REASON_PARAMETERS || reason == REASON_TEMPLATE || reason == REASON_ACCOUNT) {return;}



	//-- if Timer was set, kill it here

	EventKillTimer();



	if (ENABLE_STATUS) DrawStatus("stopped");

	if (ENABLE_SPREAD_METER) DrawSpreadInfo();







	if (MQLInfoInteger(MQL_TESTER)) {

		Print("Backtested in "+DoubleToString((GetTickCount()-FXD_MILS_INIT_END)/1000, 2)+" seconds");

		double tc = GetTickCount()-FXD_MILS_INIT_END;

		if (tc > 0)

		{

			Print("Average ticks per second: "+DoubleToString(FXD_TICKS_FROM_START/tc, 0));

		}

	}



	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 Advisor has 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;

		}

	}



	// delete dynamic pointers

	for (int i=0; i<ArraySize(_blocks_); i++)

	{

		delete _blocks_[i];

		_blocks_[i] = NULL;

	}

	ArrayResize(_blocks_, 0);



	return;

}



/************************************************************************************************************************/

// +------------------------------------------------------------------------------------------------------------------+ //

// |                                             Classes of blocks                                                    | //

// |              Classes that contain the actual code of the blocks and their input parameters as well               | //

// +------------------------------------------------------------------------------------------------------------------+ //

/************************************************************************************************************************/



/**

	The base class for all block calls

   */

class BlockCalls

{

	public:

		bool __disabled; // whether or not the block is disabled



		string __block_user_number;

        int __block_number;

		int __block_waiting;

		int __parent_number;

		int __inbound_blocks[];

		int __outbound_blocks[];



		void __addInboundBlock(int id = 0) {

			int size = ArraySize(__inbound_blocks);

			for (int i = 0; i < size; i++) {

				if (__inbound_blocks[i] == id) {

					return;

				}

			}

			ArrayResize(__inbound_blocks, size + 1);

			__inbound_blocks[size] = id;

		}



		void BlockCalls() {

			__disabled          = false;

			__block_user_number = "";

			__block_number      = 0;

			__block_waiting     = 0;

			__parent_number     = 0;

		}



		/**

		   Announce this block to the list of inbound connections of all the blocks to which this block is connected to

		   */

		void __announceThisBlock()

		{

		   // add the current block number to the list of inbound blocks

		   // for each outbound block that is provided

			for (int i = 0; i < ArraySize(__outbound_blocks); i++)

			{

				int block = __outbound_blocks[i]; // outbound block number

				int size  = ArraySize(_blocks_[block].__inbound_blocks); // the size of its inbound list



				// skip if the current block was already added

				for (int j = 0; j < size; j++) {

					if (_blocks_[block].__inbound_blocks[j] == __block_number)

					{

						return;

					}

				}



				// add the current block number to the list of inbound blocks of the other block

				ArrayResize(_blocks_[block].__inbound_blocks, size + 1);

				_blocks_[block].__inbound_blocks[size] = __block_number;

			}

		}



		// this is here, because it is used in the "run" function

		virtual void _execute_() = 0;



		/**

			In the derived class this method should be used to set dynamic parameters or other stuff before the main execute.

			This method is automatically called within the main "run" method below, before the execution of the main class.

			*/

		virtual void _beforeExecute_() {return;};

		bool _beforeExecuteEnabled; // for speed



		/**

			Same as _beforeExecute_, but to work after the execute method.

			*/

		virtual void _afterExecute_() {return;};

		bool _afterExecuteEnabled; // for speed



		/**

			This is the method that is used to run the block

			*/

		virtual void run(int _parent_=0) {

			__parent_number = _parent_;

			if (__disabled || FXD_BREAK) {return;}

			FXD_CURRENT_FUNCTION_ID = __block_number;



			if (_beforeExecuteEnabled) {_beforeExecute_();}

			_execute_();

			if (_afterExecuteEnabled) {_afterExecute_();}



			if (__block_waiting && FXD_CURRENT_FUNCTION_ID == __block_number) {fxdWait.Accumulate(FXD_CURRENT_FUNCTION_ID);}

		}

};



BlockCalls *_blocks_[];





// "Once per bar" model

template<typename T1,typename T2,typename T3>

class MDL_OncePerBar: public BlockCalls

{

	public: /* Input Parameters */

	T1 Symbol;

	T2 Period;

	T3 PassMaxTimes;

	/* Static Parameters */

	string tokens[];

	int passes[];

	datetime old_values[];

	datetime time[];

	virtual void _callback_(int r) {return;}



	public: /* Constructor */

	MDL_OncePerBar()

	{

		Symbol = (string)CurrentSymbol();

		Period = (ENUM_TIMEFRAMES)CurrentTimeframe();

		PassMaxTimes = (int)1;

	}



	public: /* The main method */

	virtual void _execute_()

	{

		// this is static for speed reasons

		

		bool next    = false;

		string token = Symbol + IntegerToString(Period);

		int index    = ArraySearch(tokens, token);

		

		if (index == -1)

		{

			index = ArraySize(tokens);

			

			ArrayResize(tokens, index + 1);

			ArrayResize(old_values, index + 1);

			ArrayResize(passes, index + 1);

			

			tokens[index] = token;

			passes[index] = 0;

			old_values[index] = 0;

		}

		

		if (PassMaxTimes > 0)

		{

			CopyTime(Symbol, Period, 1, 1, time);

			datetime new_value = time[0];

		

			if (new_value > old_values[index])

			{

				passes[index]++;

		

				if (passes[index] >= PassMaxTimes)

				{

					old_values[index]  = new_value;

					passes[index] = 0;

				}

		

				next = true;

			}

		}

		

		if (next) {_callback_(1);} else {_callback_(0);}

	}

};



// "MACD Divergence (Bearish)" model

template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6>

class MDL_macdDivBear: public BlockCalls

{

	public: /* Input Parameters */

	T1 Symbol;

	T2 fastEMA;

	T3 slowEMA;

	T4 signalSMA;

	T5 macdThreshold;

	T6 Period;

	/* Static Parameters */

	datetime BarTime;

	virtual void _callback_(int r) {return;}



	public: /* Constructor */

	MDL_macdDivBear()

	{

		Symbol = (string)CurrentSymbol();

		fastEMA = (int)12;

		slowEMA = (int)26;

		signalSMA = (int)9;

		macdThreshold = (double)0.0003;

		Period = (ENUM_TIMEFRAMES)CurrentTimeframe();

	}



	public: /* The main method */

	virtual void _execute_()

	{

		double macd[]; ArrayResize(macd,0);

		int offset1 = 0, offset2 = 0;

		double peak1 = 0, peak2 = 0;

		bool drawIt = false;

		double macd0 = 0;

		int depth = 0;

		int i = 0, j = 0;

		

		if (BarTime < (int)iTime(Symbol, Period, 1))

		{

			BarTime = (int)iTime(Symbol, Period, 1);

		

			// Loading initial data

			for (i = 0; i <= 5; i++)

			{

				ArrayResize(macd,ArraySize(macd)+1);

				macd[i] = iMACD(Symbol, Period, fastEMA, slowEMA, signalSMA, PRICE_CLOSE, 0, i);

			}

		

			// We are on macd peak now?

			if (

				   macd[1] > macdThreshold

				&& macd[2] > macdThreshold

				&& macd[3] > macdThreshold

				&& macd[4] > macdThreshold

				&& macd[1] < macd[2]

				&& macd[3] < macd[2]

				&& macd[4] < macd[2]

			)

			{

				// Locate price peak value and it's offset

				for (i = 0; i <= 15; i++)

				{

					if (

						   iHigh(Symbol, Period, i) > iHigh(Symbol, Period, i+1)

						&& iHigh(Symbol, Period, i) > iHigh(Symbol, Period, i+2)

						&& iHigh(Symbol, Period, i) > iHigh(Symbol, Period, i+3)

						&& iHigh(Symbol, Period, i) > iHigh(Symbol, Period, i+4)

					)

					{

						peak2   = iHigh(Symbol, Period, i);

						offset2 = i;

		

						break;

					}

				}

		

				// Locate previous macd peak/s

				for (i = 6; i <= iBars(Symbol, Period); i++)

				{

					ArrayResize(macd, ArraySize(macd)+1);

					macd[i] = iMACD(Symbol, Period, fastEMA, slowEMA, signalSMA, PRICE_CLOSE, 0, i);

		

					if (

						   i > 10

						&& macd[i] > macdThreshold

						&& macd[i-1] > macdThreshold

						&& macd[i-2] > macdThreshold

						&& macd[i-3] > macdThreshold

						&& macd[i-4] > macdThreshold

						&& macd[i] < macd[i-2]

						&& macd[i-1] < macd[i-2]

						&& macd[i-2] > macd[i-3]

						&& macd[i-2] > macd[i-4]

					)

					{

						if (macd0 == 0 || (macd[i-2] > macd0 && depth >= 1))

						{

							macd0 = macd[i-2];

						}

						else

						{

							break;

						}

		

						depth++;

		

						// Locate previous price peak value and it's offset

						for (j = i-4; j <= i+15; j++)

						{

							if (

								   iHigh(Symbol, Period,j) > iHigh(Symbol, Period, j+1)

								&& iHigh(Symbol, Period,j) > iHigh(Symbol, Period, j+2)

								&& iHigh(Symbol, Period,j) > iHigh(Symbol, Period, j+3)

								&& iHigh(Symbol, Period,j) > iHigh(Symbol, Period, j+4)

							)

							{

								peak1   = iHigh(Symbol, Period, j);

								offset1 = j;

		

								break;

							}

						}

		

						// Check if there is a divergence

						if (

							   depth <= 18

							&& ((macd[i-2] > macd[2] && peak1 < peak2) || (macd[i-2] < macd[2] && peak1 > peak2))

						)

						{

							drawIt = true;

		

							break;

						}

					}

				}

			}

		

			if (drawIt == true)

			{

				// Draw divergence line

				string label = "macdDivergenceBearish" + (string)TimeCurrent();

		

				ObjectCreate(0, label, OBJ_TREND, 0, iTime(Symbol, Period, offset1), iHigh(Symbol, Period, offset1), iTime(Symbol, Period, offset2), iHigh(Symbol, Period, offset2), 0, 0);

				ObjectSetInteger(0, label, OBJPROP_STYLE, STYLE_SOLID);

				ObjectSetInteger(0, label, OBJPROP_COLOR, clrDarkGray);

				ObjectSetInteger(0, label, OBJPROP_RAY, 0);

			}

		}

		

		if (drawIt == true) {_callback_(1);} else {_callback_(0);}

	}

};



// "MACD Divergence (Bullish)" model

template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6>

class MDL_macdDivBull: public BlockCalls

{

	public: /* Input Parameters */

	T1 Symbol;

	T2 fastEMA;

	T3 slowEMA;

	T4 signalSMA;

	T5 macdThreshold;

	T6 Period;

	/* Static Parameters */

	datetime BarTime;

	virtual void _callback_(int r) {return;}



	public: /* Constructor */

	MDL_macdDivBull()

	{

		Symbol = (string)CurrentSymbol();

		fastEMA = (int)12;

		slowEMA = (int)26;

		signalSMA = (int)9;

		macdThreshold = (double)0.0003;

		Period = (ENUM_TIMEFRAMES)CurrentTimeframe();

	}



	public: /* The main method */

	virtual void _execute_()

	{

		double macd[]; ArrayResize(macd,0);

		int offset1 = 0, offset2 = 0;

		double dip1 = 0, dip2 = 0;

		bool drawIt = false;

		double macd0 = 0;

		int depth = 0;

		int i = 0, j = 0;

		

		if (BarTime < (int)iTime(Symbol, Period, 1))

		{

			BarTime = (int)iTime(Symbol, Period , 1);

		

			// Loading initial data

			for (i = 0; i <= 5; i++)

			{

				ArrayResize(macd, ArraySize(macd)+1);

				macd[i] = iMACD(Symbol, Period, fastEMA, slowEMA, signalSMA, PRICE_CLOSE, 0, i);

			}

		

			// We are on macd dip now?

			if (

				   macd[1] < -1*macdThreshold

				&& macd[2] < -1*macdThreshold

				&& macd[3] < -1*macdThreshold

				&& macd[4] < -1*macdThreshold

				&& macd[1] > macd[2]

				&& macd[3] > macd[2]

				&& macd[4] > macd[2]

				)

			{

				// Locate price dip value and it's offset

				for (i = 0; i <= 15; i++)

				{

					if (

						   iLow(Symbol, Period, i) < iLow(Symbol, Period, i+1)

						&& iLow(Symbol, Period, i) < iLow(Symbol, Period, i+2)

						&& iLow(Symbol, Period, i) < iLow(Symbol, Period, i+3)

						&& iLow(Symbol, Period, i) < iLow(Symbol, Period, i+4)

					)

					{

						dip2    = iLow(Symbol, Period, i);

						offset2 = i;

		

						break;

					}

				}

		

				// Locate previous macd dip/s

				for (i = 6; i <= iBars(Symbol, Period); i++)

				{

					ArrayResize(macd, ArraySize(macd)+1);

					macd[i]=iMACD(Symbol, Period, fastEMA, slowEMA, signalSMA, PRICE_CLOSE, 0, i);

		

					if (

						   i > 10

						&& macd[i] < -1*macdThreshold

						&& macd[i-1] < -1*macdThreshold

						&& macd[i-2] < -1*macdThreshold

						&& macd[i-3] < -1*macdThreshold

						&& macd[i-4] < -1*macdThreshold

						&& macd[i] > macd[i-2]

						&& macd[i-1] > macd[i-2]

						&& macd[i-2] < macd[i-3]

						&& macd[i-2] < macd[i-4]

					 )

					{

						if (macd0 == 0 || (macd[i-2] < macd0 && depth >= 1))

						{

							macd0 = macd[i-2];

						}

						else

						{

							break;

						}

		

						depth++;

		

						// Locate previous price peak value and it's offset

						for (j = i-4; j <= i+15; j++)

						{

							if (

								   iLow(Symbol, Period, j) < iLow(Symbol, Period, j+1)

								&& iLow(Symbol, Period, j) < iLow(Symbol, Period, j+2)

								&& iLow(Symbol, Period, j) < iLow(Symbol, Period, j+3)

								&& iLow(Symbol, Period, j) < iLow(Symbol, Period, j+4)

							)

							{

								dip1    = iLow(Symbol, Period, j);

								offset1 = j;

		

								break;

							}

						}

		

						// Check if there is a divergence

						if (

							   depth <= 18

							&& ((macd[i-2] > macd[2] && dip1<dip2) || (macd[i-2] < macd[2] && dip1 > dip2))

						)

						{

							drawIt = true;

		

							break;

						}

					}

				}

			}

		

			if (drawIt == true)

			{

				// Draw divergence line

				string label = "macdDivergenceBullish" + (string)TimeCurrent();

		

				ObjectCreate(0, label, OBJ_TREND, 0, iTime(Symbol, Period, offset1), iLow(Symbol, Period, offset1), iTime(Symbol, Period, offset2), iLow(Symbol, Period, offset2), 0, 0);

				ObjectSetInteger(0, label, OBJPROP_STYLE, STYLE_SOLID);

				ObjectSetInteger(0, label, OBJPROP_COLOR, clrDarkGray);

				ObjectSetInteger(0, label, OBJPROP_RAY, 0);

			}

		}

		

		if (drawIt == true) {_callback_(1);} else {_callback_(0);}

	}

};



// "Condition" model

template<typename T1,typename _T1_,typename T2,typename T3,typename _T3_,typename T4>

class MDL_Condition: public BlockCalls

{

	public: /* Input Parameters */

	T1 Lo; virtual _T1_ _Lo_(){return(_T1_)0;}

	T2 compare;

	T3 Ro; virtual _T3_ _Ro_(){return(_T3_)0;}

	T4 crosswidth;

	virtual void _callback_(int r) {return;}



	public: /* Constructor */

	MDL_Condition()

	{

		compare = (string)">";

		crosswidth = (int)1;

	}



	public: /* The main method */

	virtual void _execute_()

	{

		bool output1 = false, output2 = false; // output 1 and output 2

		int crossover = 0;

		

		if (compare == "x>" || compare == "x<") {crossover = 1;}

		

		for (int i = 0; i <= crossover; i++)

		{

			// i=0 - normal pass, i=1 - crossover pass

		

			// Left operand of the condition

			FXD_MORE_SHIFT = i * crosswidth;

			_T1_ lo = _Lo_();

			if (MathAbs(lo) == EMPTY_VALUE) {return;}

		

			// Right operand of the condition

			FXD_MORE_SHIFT = i * crosswidth;

			_T3_ ro = _Ro_();

			if (MathAbs(ro) == EMPTY_VALUE) {return;}

		

			// Conditions

			if (CompareValues(compare, lo, ro))

			{

				if (i == 0)

				{

					output1 = true;

				}

			}

			else

			{

				if (i == 0)

				{

					output2 = true;

				}

				else

				{

					output2 = false;

				}

			}

		

			if (crossover == 1)

			{

				if (CompareValues(compare, ro, lo))

				{

					if (i == 0)

					{

						output2 = true;

					}

				}

				else

				{

					if (i == 1)

					{

						output1 = false;

					}

				}

			}

		}

		

		FXD_MORE_SHIFT = 0; // reset

		

			  if (output1 == true) {_callback_(1);}

		else if (output2 == true) {_callback_(0);}

	}

};



// "Indicator moves within limits" model

template<typename T1,typename _T1_,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename _T7_,typename T8,typename T9,typename T10,typename _T10_>

class MDL_IndicatorWithinLimits: public BlockCalls

{

	public: /* Input Parameters */

	T1 Indicator; virtual _T1_ _Indicator_(){return(_T1_)0;}

	T2 CandlesShift;

	T3 CandlesPeriod;

	T4 ExceptionCandles;

	T5 UpperLevelMode;

	T6 UpperLevel;

	T7 dUpperLevel; virtual _T7_ _dUpperLevel_(){return(_T7_)0;}

	T8 LowerLevelMode;

	T9 LowerLevel;

	T10 dLowerLevel; virtual _T10_ _dLowerLevel_(){return(_T10_)0;}

	/* Static Parameters */

	datetime last_bar_time;

	bool failed;

	virtual void _callback_(int r) {return;}



	public: /* Constructor */

	MDL_IndicatorWithinLimits()

	{

		CandlesShift = (int)1;

		CandlesPeriod = (int)10;

		ExceptionCandles = (int)0;

		UpperLevelMode = (string)"fixed";

		UpperLevel = (double)70.0;

		LowerLevelMode = (string)"fixed";

		LowerLevel = (double)30.0;

		/* Static Parameters (initial value) */

		last_bar_time =  0;

		failed =  0;

	}



	public: /* The main method */

	virtual void _execute_()

	{

		int last_candle  = CandlesShift + CandlesPeriod - 1;

		int count_true   = 0; // the count of candles where the value is within the limits

		int count_failed = 0; // the count of candles where the value is outside limits

		

		//int count_needed = CandlesPeriod;

		//if (ExceptionCandles > 0) {

		//	count_needed = CandlesPeriod - ExceptionCandles;

		//}

		

		for (int i=CandlesShift; i<=last_candle; i++)

		{

			

			// TO DO: if CandleShift==0 (first candle) to check only this candle if older candles are checked.

			// don't forget to check candle 0 time

			// don't forget to check exceptions

			

			/*

			// this is the cache, but I removed it because of specific situation

			if (i==CandlesShift && CandlesShift>0) {

				datetime current_bar_time=iTime(CurrentSymbol(),CurrentTimeframe(),0);

				if (last_bar_time==current_bar_time) {break;} else {failed=false;}

				last_bar_time=current_bar_time;

			}

			*/

		

			failed = false;

		

			FXD_MORE_SHIFT = i;

			_T1_ ivalue = _Indicator_();

			FXD_MORE_SHIFT = 0;

			

			double uplevel = EMPTY_VALUE;

			double dnlevel = -EMPTY_VALUE;

			

			if (UpperLevelMode != "")

			{

				if (UpperLevelMode == "fixed")

				{

					uplevel = UpperLevel;

				}

				else 

				//if (UpperLevelMode == "dynamic")

				{

					FXD_MORE_SHIFT = i;

					uplevel        = _dUpperLevel_();

					FXD_MORE_SHIFT = 0;

				}

			}

		

			if (LowerLevelMode != "")

			{

				if (LowerLevelMode == "fixed")

				{

					dnlevel = LowerLevel;

				}

				else

				//if (LowerLevelMode=="dynamic")

				{

					FXD_MORE_SHIFT = i;

					dnlevel        = _dLowerLevel_();

					FXD_MORE_SHIFT = 0;

				}

			}

			

			//-- levels are inverted, normalize them

			if (uplevel < dnlevel)

			{

				double tmplevel = uplevel;

				uplevel = dnlevel;

				dnlevel = tmplevel;

			}

			

			if (ivalue > uplevel || ivalue < dnlevel)

			{

				failed = true;

			}

		

			if (failed == true)

			{

				if (ExceptionCandles <= 0)

				{

					break;

				}

				else

				{

					count_failed++;

		

					if (count_failed > ExceptionCandles)

					{

						break;

					}

				}

			}

		

		  	//if (failed==false) {

			//	count_true++;

			//	if (count_true >= count_needed) {break;}

			//}

		}

		

		FXD_MORE_SHIFT = 0;

		

		if (failed == false) {_callback_(1);} else {_callback_(0);}

	}

};



// "Alert message" model

template<typename T1,typename T2,typename T3,typename _T3_,typename T4,typename T5,typename _T5_,typename T6,typename T7,typename _T7_,typename T8,typename T9,typename _T9_,typename T10,typename T11,typename _T11_,typename T12,typename T13,typename _T13_,typename T14,typename T15,typename _T15_,typename T16,typename T17,typename _T17_,typename T18,typename T19,typename _T19_,typename T20,typename T21,typename _T21_,typename T22>

class MDL_AlertMessageAdvanced: public BlockCalls

{

	public: /* Input Parameters */

	T1 AlertTitle;

	T2 AlertLabel1;

	T3 AlertValue1; virtual _T3_ _AlertValue1_(){return(_T3_)0;}

	T4 AlertLabel2;

	T5 AlertValue2; virtual _T5_ _AlertValue2_(){return(_T5_)0;}

	T6 AlertLabel3;

	T7 AlertValue3; virtual _T7_ _AlertValue3_(){return(_T7_)0;}

	T8 AlertLabel4;

	T9 AlertValue4; virtual _T9_ _AlertValue4_(){return(_T9_)0;}

	T10 AlertLabel5;

	T11 AlertValue5; virtual _T11_ _AlertValue5_(){return(_T11_)0;}

	T12 AlertLabel6;

	T13 AlertValue6; virtual _T13_ _AlertValue6_(){return(_T13_)0;}

	T14 AlertLabel7;

	T15 AlertValue7; virtual _T15_ _AlertValue7_(){return(_T15_)0;}

	T16 AlertLabel8;

	T17 AlertValue8; virtual _T17_ _AlertValue8_(){return(_T17_)0;}

	T18 AlertLabel9;

	T19 AlertValue9; virtual _T19_ _AlertValue9_(){return(_T19_)0;}

	T20 AlertLabel10;

	T21 AlertValue10; virtual _T21_ _AlertValue10_(){return(_T21_)0;}

	T22 AlsoSendNotification;

	virtual void _callback_(int r) {return;}



	public: /* Constructor */

	MDL_AlertMessageAdvanced()

	{

		AlertTitle = (string)"Alert Message";

		AlertLabel1 = (string)"";

		AlertLabel2 = (string)"";

		AlertLabel3 = (string)"";

		AlertLabel4 = (string)"";

		AlertLabel5 = (string)"";

		AlertLabel6 = (string)"";

		AlertLabel7 = (string)"";

		AlertLabel8 = (string)"";

		AlertLabel9 = (string)"";

		AlertLabel10 = (string)"";

		AlsoSendNotification = (bool)false;

	}



	public: /* The main method */

	virtual void _execute_()

	{

		string text = "";

		

		if (AlertLabel1 != "") {text += "\n" + AlertLabel1 + ": " + (string)(_AlertValue1_());}

		if (AlertLabel2 != "") {text += "\n" + AlertLabel2 + ": " + (string)(_AlertValue2_());}

		if (AlertLabel3 != "") {text += "\n" + AlertLabel3 + ": " + (string)(_AlertValue3_());}

		if (AlertLabel4 != "") {text += "\n" + AlertLabel4 + ": " + (string)(_AlertValue4_());}

		if (AlertLabel5 != "") {text += "\n" + AlertLabel5 + ": " + (string)(_AlertValue5_());}

		if (AlertLabel6 != "") {text += "\n" + AlertLabel6 + ": " + (string)(_AlertValue6_());}

		if (AlertLabel7 != "") {text += "\n" + AlertLabel7 + ": " + (string)(_AlertValue7_());}

		if (AlertLabel8 != "") {text += "\n" + AlertLabel8 + ": " + (string)(_AlertValue8_());}

		if (AlertLabel9 != "") {text += "\n" + AlertLabel9 + ": " + (string)(_AlertValue9_());}

		if (AlertLabel10 != "") {text += "\n" + AlertLabel10 + ": " + (string)(_AlertValue10_());}

		

		text = AlertTitle + "\n" + text;

		

		Alert(text);

		

		if (AlsoSendNotification==true) SendNotification(text);

		

		_callback_(1);

	}

};



// "Draw Arrow" model

template<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename _T6_,typename T7,typename _T7_,typename T8,typename T9,typename T10,typename T11,typename T12,typename T13,typename T14,typename T15,typename T16,typename T17>

class MDL_ChartDrawArrow: public BlockCalls

{

	public: /* Input Parameters */

	T1 ObjectPerBar;

	T2 ObjectUpdate;

	T3 ObjName;

	T4 ObjectType;

	T5 ObjArrowCode;

	T6 ObjTime1; virtual _T6_ _ObjTime1_(){return(_T6_)0;}

	T7 ObjPrice1; virtual _T7_ _ObjPrice1_(){return(_T7_)0;}

	T8 ObjAnchor;

	T9 ObjColor;

	T10 ObjStyle;

	T11 ObjWidth;

	T12 ObjBack;

	T13 ObjSelectable;

	T14 ObjSelected;

	T15 ObjHidden;

	T16 ObjZorder;

	T17 ObjChartSubWindow;

	/* Static Parameters */

	int count;

	datetime time0;

	virtual void _callback_(int r) {return;}



	public: /* Constructor */

	MDL_ChartDrawArrow()

	{

		ObjectPerBar = (bool)true;

		ObjectUpdate = (bool)true;

		ObjName = (string)"";

		ObjectType = (ENUM_OBJECT)OBJ_ARROW_UP;

		ObjArrowCode = (int)58;

		ObjAnchor = (int)ANCHOR_TOP;

		ObjColor = (color)clrDeepPink;

		ObjStyle = (ENUM_LINE_STYLE)STYLE_SOLID;

		ObjWidth = (int)1;

		ObjBack = (bool)false;

		ObjSelectable = (bool)true;

		ObjSelected = (bool)false;

		ObjHidden = (bool)false;

		ObjZorder = (int)0;

		ObjChartSubWindow = (string)"";

		/* Static Parameters (initial value) */

		count =  0;

		time0 =  0;

	}



	public: /* The main method */

	virtual void _execute_()

	{

		string ObjNamePrefix = "fxd_arrow_";

		long ObjChartID      = 0;

		int subwindow_id     = WindowFindVisible(ObjChartID, ObjChartSubWindow);

		

		if (subwindow_id >= 0)

		{

			string name       = "";

			string name_base  = "";

			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 = ObjNamePrefix + __block_user_number + "_";}

		

				if (get_new_name == false)

				{

					name = name_base + IntegerToString(count);

				}

				else

				{

					while (true)

					{

						count++;

						name = name_base + IntegerToString(count);

		

						if (ObjectFind(ObjChartID,name) < 0) {break;}

					}

				}

		

				if (ObjName != "" && count == 0) {name = ObjName;}

		

				if (ObjectFind(ObjChartID,name) < 0 && !ObjectCreate(ObjChartID,name,(ENUM_OBJECT)ObjectType,subwindow_id,0,0))

				{

					Print(__FUNCTION__,": failed to create arrow object! Error code = ",GetLastError());

				}

		

				if (ObjectType == OBJ_ARROW) ObjectSetInteger(ObjChartID,name,OBJPROP_ARROWCODE,ObjArrowCode);

		

				ObjectSetInteger(ObjChartID,name,OBJPROP_TIME,0,(long)_ObjTime1_());

				ObjectSetDouble(ObjChartID,name,OBJPROP_PRICE,0,(double)_ObjPrice1_());

				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();

			}

		}

		

		_callback_(1);

	}

};





//------------------------------------------------------------------------------------------------------------------------



// "Stochastic Oscillator" model

class MDLIC_indicators_iStochastic

{

	public: /* Input Parameters */

	int Kperiod;

	int Dperiod;

	int Slowing;

	ENUM_MA_METHOD MAmethod;

	ENUM_STO_PRICE PriceField;

	int Mode;

	string Symbol;

	ENUM_TIMEFRAMES Period;

	int Shift;

	virtual void _callback_(int r) {return;}



	public: /* Constructor */

	MDLIC_indicators_iStochastic()

	{

		Kperiod = (int)5;

		Dperiod = (int)3;

		Slowing = (int)3;

		MAmethod = (ENUM_MA_METHOD)MODE_SMA;

		PriceField = (ENUM_STO_PRICE)STO_LOWHIGH;

		Mode = (int)0;

		Symbol = (string)CurrentSymbol();

		Period = (ENUM_TIMEFRAMES)CurrentTimeframe();

		Shift = (int)0;

	}



	public: /* The main method */

	double _execute_()

	{

		return iStochastic(Symbol, Period, Kperiod, Dperiod, Slowing, MAmethod, PriceField, Mode, Shift + FXD_MORE_SHIFT);

	}

};



// "Numeric" model

class MDLIC_value_value

{

	public: /* Input Parameters */

	double Value;

	virtual void _callback_(int r) {return;}



	public: /* Constructor */

	MDLIC_value_value()

	{

		Value = (double)1.0;

	}



	public: /* The main method */

	double _execute_()

	{

		return Value;

	}

};



// "Time" model

class MDLIC_value_time

{

	public: /* Input Parameters */

	int ModeTime;

	int TimeSource;

	string TimeStamp;

	int TimeCandleID;

	string TimeMarket;

	ENUM_TIMEFRAMES TimeCandleTimeframe;

	int TimeComponentYear;

	int TimeComponentMonth;

	double TimeComponentDay;

	double TimeComponentHour;

	double TimeComponentMinute;

	int TimeComponentSecond;

	datetime TimeValue;

	int ModeTimeShift;

	int TimeShiftYears;

	int TimeShiftMonths;

	int TimeShiftWeeks;

	double TimeShiftDays;

	double TimeShiftHours;

	double TimeShiftMinutes;

	int TimeShiftSeconds;

	bool TimeSkipWeekdays;

	/* Static Parameters */

	datetime retval;

	datetime retval0;

	datetime Time[];

	virtual void _callback_(int r) {return;}



	public: /* Constructor */

	MDLIC_value_time()

	{

		ModeTime = (int)0;

		TimeSource = (int)0;

		TimeStamp = (string)"00:00";

		TimeCandleID = (int)1;

		TimeMarket = (string)"";

		TimeCandleTimeframe = (ENUM_TIMEFRAMES)0;

		TimeComponentYear = (int)0;

		TimeComponentMonth = (int)0;

		TimeComponentDay = (double)0.0;

		TimeComponentHour = (double)12.0;

		TimeComponentMinute = (double)0.0;

		TimeComponentSecond = (int)0;

		TimeValue = (datetime)0;

		ModeTimeShift = (int)0;

		TimeShiftYears = (int)0;

		TimeShiftMonths = (int)0;

		TimeShiftWeeks = (int)0;

		TimeShiftDays = (double)0.0;

		TimeShiftHours = (double)0.0;

		TimeShiftMinutes = (double)0.0;

		TimeShiftSeconds = (int)0;

		TimeSkipWeekdays = (bool)false;

		/* Static Parameters (initial value) */

		retval =  0;

		retval0 =  0;

	}



	public: /* The main method */

	datetime _execute_()

	{

		// this is static for speed reasons

		

		if (TimeMarket == "") TimeMarket = Symbol();

		

		if (ModeTime == 0)

		{

			     if (TimeSource == 0) {retval = TimeCurrent();}

			else if (TimeSource == 1) {retval = TimeLocal() + (TimeCurrent() - TimeLocal());}

			else if (TimeSource == 2) {retval = TimeGMT() + (TimeCurrent() - TimeGMT());}

		}

		else if (ModeTime == 1)

		{

			retval  = StringToTime(TimeStamp);

			retval0 = retval;

		}

		else if (ModeTime==2)

		{

			retval = TimeFromComponents(TimeSource, TimeComponentYear, TimeComponentMonth, TimeComponentDay, TimeComponentHour, TimeComponentMinute, TimeComponentSecond);

		}

		else if (ModeTime == 3)

		{

			ArraySetAsSeries(Time,true);

			CopyTime(TimeMarket,TimeCandleTimeframe,TimeCandleID,1,Time);

			retval = Time[0];

		}

		else if (ModeTime == 4)

		{

			retval = TimeValue;

		}

		

		if (ModeTimeShift > 0)

		{

			int sh = 1;

		

			if (ModeTimeShift == 1) {sh = -1;}

		

			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    = (int)MathFloor(TimeComponentDay);

					hour   = (int)(MathFloor(TimeComponentHour) + (24 * (TimeComponentDay - MathFloor(TimeComponentDay))));

					minute = (int)(MathFloor(TimeComponentMinute) + (60 * (TimeComponentHour - MathFloor(TimeComponentHour))));

					second = (int)(TimeComponentSecond + (60 * (TimeComponentMinute - MathFloor(TimeComponentMinute))));

				}

				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 = StringToTime(IntegerToString(year)+"."+IntegerToString(month)+"."+IntegerToString(day)+" "+IntegerToString(hour)+":"+IntegerToString(minute)+":"+IntegerToString(second));

			}

		

			retval = retval + (sh * ((604800 * TimeShiftWeeks) + SecondsFromComponents(TimeShiftDays, TimeShiftHours, TimeShiftMinutes, TimeShiftSeconds)));

		

			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;}

				}

			}

		}

		

		

		return (datetime)retval;

	}

};



// "Candle" model

class MDLIC_candles_candles

{

	public: /* Input Parameters */

	string iOHLC;

	string ModeCandleFindBy;

	int CandleID;

	string TimeStamp;

	string Symbol;

	ENUM_TIMEFRAMES Period;

	virtual void _callback_(int r) {return;}



	public: /* Constructor */

	MDLIC_candles_candles()

	{

		iOHLC = (string)"iClose";

		ModeCandleFindBy = (string)"id";

		CandleID = (int)0;

		TimeStamp = (string)"00:00";

		Symbol = (string)CurrentSymbol();

		Period = (ENUM_TIMEFRAMES)CurrentTimeframe();

	}



	public: /* The main method */

	double _execute_()

	{

		int digits = (int)SymbolInfoInteger(Symbol, SYMBOL_DIGITS);

		

		double O[];

		double H[];

		double L[];

		double C[]; 

		long cTickVolume[];

		long cRealVolume[];

		datetime T[];

		

		double retval = EMPTY_VALUE;

		

		// candle's id will change, so we don't want to mess with the variable CandleID;

		int cID = CandleID;

		

		if (ModeCandleFindBy == "time")

		{

			cID = iCandleID(Symbol, Period, StringToTimeEx(TimeStamp, "server"));

		}

		

		cID = cID + FXD_MORE_SHIFT;

		

		//-- the common levels ----------------------------------------------------

		if (iOHLC == "iOpen")

		{

			if (CopyOpen(Symbol,Period,cID,1,O) > -1) retval = O[0];

		}

		else if (iOHLC == "iHigh")

		{

			if (CopyHigh(Symbol,Period,cID,1,H) > -1) retval = H[0];

		}

		else if (iOHLC == "iLow")

		{

			if (CopyLow(Symbol,Period,cID,1,L) > -1) retval = L[0];

		}

		else if (iOHLC == "iClose")

		{

			if (CopyClose(Symbol,Period,cID,1,C) > -1) retval = C[0];

		}

		

		//-- non-price values  ----------------------------------------------------

		else if (iOHLC == "iVolume" || iOHLC == "iTickVolume")

		{

			if (CopyTickVolume(Symbol,Period,cID,1,cTickVolume) > -1) retval = (double)cTickVolume[0];

			

			return retval;

		}

		else if (iOHLC == "iRealVolume")

		{

			if (CopyRealVolume(Symbol,Period,cID,1,cRealVolume) > -1) retval = (double)cRealVolume[0];

			

			return retval;

		}

		else if (iOHLC == "iTime")

		{

			if (CopyTime(Symbol,Period,cID,1,T) > -1) retval = (double)T[0];

			

			return retval;

		}

		

		//-- simple calculations --------------------------------------------------

		else if (iOHLC == "iMedian")

		{

			if (

				   CopyLow(Symbol,Period,cID,1,L) > -1

				&& CopyHigh(Symbol,Period,cID,1,H) > -1

			)

			{

				retval = ((L[0]+H[0])/2);

			}

		}

		else if (iOHLC == "iTypical")

		{

			if (

				   CopyLow(Symbol,Period,cID,1,L) > -1

				&& CopyHigh(Symbol,Period,cID,1,H) > -1

				&& CopyClose(Symbol,Period,cID,1,C) > -1

			)

			{

				retval = ((L[0]+H[0]+C[0])/3);

			}

		}

		else if (iOHLC == "iAverage")

		{

			if (

				   CopyLow(Symbol,Period,cID,1,L) > -1

				&& CopyHigh(Symbol,Period,cID,1,H) > -1

				&& CopyClose(Symbol,Period,cID,1,C) > -1

			)

			{

				retval = ((L[0]+H[0]+C[0]+C[0])/4);

			}

		}

		

		//-- more complex levels --------------------------------------------------

		else if (iOHLC=="iTotal")

		{

			if (

				   CopyHigh(Symbol,Period,cID,1,H) > -1

				&& CopyLow(Symbol,Period,cID,1,L) > -1

			)

			{

				retval = toPips(MathAbs(H[0]-L[0]),Symbol);

			}

		}

		else if (iOHLC == "iBody")

		{

			if (

				   CopyOpen(Symbol,Period,cID,1,O) > -1

				&& CopyClose(Symbol,Period,cID,1,C) > -1

			)

			{

				retval = toPips(MathAbs(C[0]-O[0]),Symbol);

			}

		}

		else if (iOHLC == "iUpperWick")

		{

			if (

				   CopyHigh(Symbol,Period,cID,1,H) > -1

				&& CopyOpen(Symbol,Period,cID,1,O) > -1

				&& CopyClose(Symbol,Period,cID,1,C) > -1

				&& CopyLow(Symbol,Period,cID,1,L) > -1

			)

			{

				retval = (C[0] > O[0]) ? toPips(MathAbs(H[0]-C[0]),Symbol) : toPips(MathAbs(H[0]-O[0]),Symbol);

			}

		}

		else if (iOHLC == "iBottomWick")

		{

			if (

				   CopyHigh(Symbol,Period,cID,1,H) > -1

				&& CopyOpen(Symbol,Period,cID,1,O) > -1

				&& CopyClose(Symbol,Period,cID,1,C) > -1

				&& CopyLow(Symbol,Period,cID,1,L) > -1

			)

			{

				retval = (C[0] > O[0]) ? toPips(MathAbs(O[0]-L[0]),Symbol) : toPips(MathAbs(C[0]-L[0]),Symbol);

			}

		}

		else if (iOHLC == "iGap")

		{

			if (

				   CopyOpen(Symbol,Period,cID,1,O) > -1

				&& CopyClose(Symbol,Period,cID+1,1,C) > -1

			)

			{

				retval = toPips(MathAbs(O[0]-C[0]),Symbol);

			}

		}

		else if (iOHLC == "iBullTotal")

		{

			if (

				   CopyOpen(Symbol,Period,cID,1,O) > -1

				&& CopyClose(Symbol,Period,cID,1,C) > -1

				&& CopyHigh(Symbol,Period,cID,1,H) > -1

				&& CopyLow(Symbol,Period,cID,1,L) > -1

				&& C[0] > O[0]

			)

			{

				retval = toPips((H[0]-L[0]),Symbol);

			}

		}

		else if (iOHLC == "iBullBody")

		{

			if (

				   CopyOpen(Symbol,Period,cID,1,O) > -1

				&& CopyClose(Symbol,Period,cID,1,C) > -1

				&& C[0] > O[0]

			)

			{

				retval = toPips((C[0]-O[0]),Symbol);

			}

		}

		else if (iOHLC == "iBullUpperWick")

		{

			if (

				   CopyHigh(Symbol,Period,cID,1,H) > -1

				&& CopyOpen(Symbol,Period,cID,1,O) > -1

				&& CopyClose(Symbol,Period,cID,1,C) > -1

				&& C[0] > O[0]

			)

			{

				retval = toPips((H[0]-C[0]),Symbol);

			}

		}

		else if (iOHLC == "iBullBottomWick")

		{

			if (

				   CopyLow(Symbol,Period,cID,1,L) > -1

				&& CopyOpen(Symbol,Period,cID,1,O) > -1

				&& CopyClose(Symbol,Period,cID,1,C) > -1

				&& C[0] > O[0]

			)

			{

				retval = toPips((O[0]-L[0]),Symbol);

			}

		}

		else if (iOHLC == "iBearTotal")

		{

			if (

				   CopyOpen(Symbol,Period,cID,1,O) > -1

				&& CopyClose(Symbol,Period,cID,1,C) > -1

				&& CopyHigh(Symbol,Period,cID,1,H) > -1

				&& CopyLow(Symbol,Period,cID,1,L) > -1

				&& C[0] < O[0]

			)

			{

				retval = toPips((H[0]-L[0]),Symbol);

			}

		}

		else if (iOHLC == "iBearBody")

		{

			if (

				   CopyOpen(Symbol,Period,cID,1,O) > -1

				&& CopyClose(Symbol,Period,cID,1,C) > -1

				&& C[0] < O[0]

			)

			{

				retval = toPips((O[0]-C[0]),Symbol);

			}

		}

		else if (iOHLC == "iBearUpperWick")

		{

			if (

				   CopyHigh(Symbol,Period,cID,1,H) > -1

				&& CopyOpen(Symbol,Period,cID,1,O) > -1

				&& CopyClose(Symbol,Period,cID,1,C) > -1

				&& C[0] < O[0]

			)

			{

				retval = toPips((H[0]-O[0]),Symbol);

			}

		}

		else if (iOHLC == "iBearBottomWick")

		{

			if (

				   CopyLow(Symbol,Period,cID,1,L) > -1

				&& CopyOpen(Symbol,Period,cID,1,O) > -1

				&& CopyClose(Symbol,Period,cID,1,C) > -1

				&& C[0] < O[0]

			)

			{

				retval = toPips((C[0]-L[0]),Symbol);

			}

		}

		

		return NormalizeDouble(retval, digits);

	}

};





//------------------------------------------------------------------------------------------------------------------------



// Block 2 (Once per bar)

class Block0: public MDL_OncePerBar<string,ENUM_TIMEFRAMES,int>

{



	public: /* Constructor */

	Block0() {

		__block_number = 0;

		__block_user_number = "2";

		_beforeExecuteEnabled = true;



		// Fill the list of outbound blocks

		int ___outbound_blocks[2] = {1,2};

		ArrayCopy(__outbound_blocks, ___outbound_blocks);

	}



	public: /* Callback & Run */

	virtual void _callback_(int value) {

		if (value == 1) {

			_blocks_[1].run(0);

			_blocks_[2].run(0);

		}

	}



	virtual void _beforeExecute_()

	{



		Symbol = (string)CurrentSymbol();

		Period = (ENUM_TIMEFRAMES)CurrentTimeframe();

	}

};



// Block 3 (MACD Divergence (Bearish))

class Block1: public MDL_macdDivBear<string,int,int,int,double,ENUM_TIMEFRAMES>

{



	public: /* Constructor */

	Block1() {

		__block_number = 1;

		__block_user_number = "3";

		_beforeExecuteEnabled = true;



		// Fill the list of outbound blocks

		int ___outbound_blocks[1] = {4};

		ArrayCopy(__outbound_blocks, ___outbound_blocks);

	}



	public: /* Callback & Run */

	virtual void _callback_(int value) {

		if (value == 1) {

			_blocks_[4].run(1);

		}

	}



	virtual void _beforeExecute_()

	{



		Symbol = (string)CurrentSymbol();

		fastEMA = (int)_externs::inp3_fastEMA;

		slowEMA = (int)_externs::inp3_slowEMA;

		signalSMA = (int)_externs::inp3_signalSMA;

		macdThreshold = (double)_externs::inp3_macdThreshold;

		Period = (ENUM_TIMEFRAMES)_externs::inp3_Period;

	}

};



// Block 4 (MACD Divergence (Bullish))

class Block2: public MDL_macdDivBull<string,int,int,int,double,ENUM_TIMEFRAMES>

{



	public: /* Constructor */

	Block2() {

		__block_number = 2;

		__block_user_number = "4";

		_beforeExecuteEnabled = true;



		// Fill the list of outbound blocks

		int ___outbound_blocks[1] = {3};

		ArrayCopy(__outbound_blocks, ___outbound_blocks);

	}



	public: /* Callback & Run */

	virtual void _callback_(int value) {

		if (value == 1) {

			_blocks_[3].run(2);

		}

	}



	virtual void _beforeExecute_()

	{



		Symbol = (string)CurrentSymbol();

		fastEMA = (int)_externs::inp4_fastEMA;

		slowEMA = (int)_externs::inp4_slowEMA;

		signalSMA = (int)_externs::inp4_signalSMA;

		macdThreshold = (double)_externs::inp4_macdThreshold;

		Period = (ENUM_TIMEFRAMES)_externs::inp4_Period;

	}

};



// Block 5 (Condition)

class Block3: public MDL_Condition<MDLIC_indicators_iStochastic,double,string,MDLIC_indicators_iStochastic,double,int>

{



	public: /* Constructor */

	Block3() {

		__block_number = 3;

		__block_user_number = "5";





		// Fill the list of outbound blocks

		int ___outbound_blocks[1] = {5};

		ArrayCopy(__outbound_blocks, ___outbound_blocks);



		// IC input parameters

		Lo.Shift = 1;

		Ro.Shift = 1;

	}



	public: /* Custom methods */

	virtual double _Lo_() {

		Lo.Kperiod = _externs::inp5_Lo_Kperiod;

		Lo.Dperiod = _externs::inp5_Lo_Dperiod;

		Lo.Slowing = _externs::inp5_Lo_Slowing;

		Lo.MAmethod = MODE_SMA;

		Lo.PriceField = STO_LOWHIGH;

		Lo.Mode = _externs::inp5_Lo_Mode;

		Lo.Symbol = CurrentSymbol();

		Lo.Period = _externs::inp5_Lo_Period;



		return Lo._execute_();

	}

	virtual double _Ro_() {

		Ro.Kperiod = _externs::inp5_Ro_Kperiod;

		Ro.Dperiod = _externs::inp5_Ro_Dperiod;

		Ro.Slowing = _externs::inp5_Ro_Slowing;

		Ro.MAmethod = MODE_SMA;

		Ro.PriceField = STO_LOWHIGH;

		Ro.Mode = _externs::inp5_Ro_Mode;

		Ro.Symbol = CurrentSymbol();

		Ro.Period = _externs::inp5_Ro_Period;



		return Ro._execute_();

	}



	public: /* Callback & Run */

	virtual void _callback_(int value) {

		if (value == 1) {

			_blocks_[5].run(3);

		}

	}

};



// Block 6 (Condition)

class Block4: public MDL_Condition<MDLIC_indicators_iStochastic,double,string,MDLIC_indicators_iStochastic,double,int>

{



	public: /* Constructor */

	Block4() {

		__block_number = 4;

		__block_user_number = "6";





		// Fill the list of outbound blocks

		int ___outbound_blocks[1] = {6};

		ArrayCopy(__outbound_blocks, ___outbound_blocks);



		// IC input parameters

		Lo.Shift = 1;

		Ro.Shift = 1;

		// Block input parameters

		compare = "<";

	}



	public: /* Custom methods */

	virtual double _Lo_() {

		Lo.Kperiod = _externs::inp6_Lo_Kperiod;

		Lo.Dperiod = _externs::inp6_Lo_Dperiod;

		Lo.Slowing = _externs::inp6_Lo_Slowing;

		Lo.MAmethod = MODE_SMA;

		Lo.PriceField = STO_LOWHIGH;

		Lo.Mode = _externs::inp6_Lo_Mode;

		Lo.Symbol = CurrentSymbol();

		Lo.Period = _externs::inp6_Lo_Period;



		return Lo._execute_();

	}

	virtual double _Ro_() {

		Ro.Kperiod = _externs::inp6_Ro_Kperiod;

		Ro.Dperiod = _externs::inp6_Ro_Dperiod;

		Ro.Slowing = _externs::inp6_Ro_Slowing;

		Ro.MAmethod = MODE_SMA;

		Ro.PriceField = STO_LOWHIGH;

		Ro.Mode = _externs::inp6_Ro_Mode;

		Ro.Symbol = CurrentSymbol();

		Ro.Period = _externs::inp6_Ro_Period;



		return Ro._execute_();

	}



	public: /* Callback & Run */

	virtual void _callback_(int value) {

		if (value == 1) {

			_blocks_[6].run(4);

		}

	}

};



// Block 9 (Indicator moves within limits)

class Block5: public MDL_IndicatorWithinLimits<MDLIC_indicators_iStochastic,double,int,int,int,string,double,MDLIC_value_value,double,string,double,MDLIC_value_value,double>

{



	public: /* Constructor */

	Block5() {

		__block_number = 5;

		__block_user_number = "9";

		_beforeExecuteEnabled = true;



		// Fill the list of outbound blocks

		int ___outbound_blocks[1] = {7};

		ArrayCopy(__outbound_blocks, ___outbound_blocks);



		// IC input parameters

		Indicator.Shift = 1;

		dUpperLevel.Value = 70.0;

		dLowerLevel.Value = 30.0;

	}



	public: /* Custom methods */

	virtual double _Indicator_() {

		Indicator.Kperiod = _externs::inp9_Indicator_Kperiod;

		Indicator.Dperiod = _externs::inp9_Indicator_Dperiod;

		Indicator.Slowing = _externs::inp9_Indicator_Slowing;

		Indicator.MAmethod = MODE_SMA;

		Indicator.PriceField = STO_LOWHIGH;

		Indicator.Symbol = CurrentSymbol();

		Indicator.Period = _externs::inp9_Indicator_Period;



		return Indicator._execute_();

	}

	virtual double _dUpperLevel_() {return dUpperLevel._execute_();}

	virtual double _dLowerLevel_() {return dLowerLevel._execute_();}



	public: /* Callback & Run */

	virtual void _callback_(int value) {

		if (value == 1) {

			_blocks_[7].run(5);

		}

	}



	virtual void _beforeExecute_()

	{



		CandlesShift = (int)_externs::inp9_CandlesShift;

		CandlesPeriod = (int)_externs::inp9_CandlesPeriod;

		ExceptionCandles = (int)_externs::inp9_ExceptionCandles;

		UpperLevel = (double)_externs::inp9_UpperLevel;

		LowerLevel = (double)_externs::inp9_LowerLevel;

	}

};



// Block 10 (Indicator moves within limits)

class Block6: public MDL_IndicatorWithinLimits<MDLIC_indicators_iStochastic,double,int,int,int,string,double,MDLIC_value_value,double,string,double,MDLIC_value_value,double>

{



	public: /* Constructor */

	Block6() {

		__block_number = 6;

		__block_user_number = "10";

		_beforeExecuteEnabled = true;



		// Fill the list of outbound blocks

		int ___outbound_blocks[1] = {8};

		ArrayCopy(__outbound_blocks, ___outbound_blocks);



		// IC input parameters

		Indicator.Shift = 1;

		dUpperLevel.Value = 70.0;

		dLowerLevel.Value = 30.0;

	}



	public: /* Custom methods */

	virtual double _Indicator_() {

		Indicator.Kperiod = _externs::inp10_Indicator_Kperiod;

		Indicator.Dperiod = _externs::inp10_Indicator_Dperiod;

		Indicator.Slowing = _externs::inp10_Indicator_Slowing;

		Indicator.MAmethod = MODE_SMA;

		Indicator.PriceField = STO_LOWHIGH;

		Indicator.Symbol = CurrentSymbol();

		Indicator.Period = _externs::inp10_Indicator_Period;



		return Indicator._execute_();

	}

	virtual double _dUpperLevel_() {return dUpperLevel._execute_();}

	virtual double _dLowerLevel_() {return dLowerLevel._execute_();}



	public: /* Callback & Run */

	virtual void _callback_(int value) {

		if (value == 1) {

			_blocks_[8].run(6);

		}

	}



	virtual void _beforeExecute_()

	{



		CandlesShift = (int)_externs::inp10_CandlesShift;

		CandlesPeriod = (int)_externs::inp10_CandlesPeriod;

		ExceptionCandles = (int)_externs::inp10_ExceptionCandles;

		UpperLevel = (double)_externs::inp10_UpperLevel;

		LowerLevel = (double)_externs::inp10_LowerLevel;

	}

};



// Block 14 (Alert message)

class Block7: public MDL_AlertMessageAdvanced<string,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,bool>

{



	public: /* Constructor */

	Block7() {

		__block_number = 7;

		__block_user_number = "14";

		_beforeExecuteEnabled = true;



		// Fill the list of outbound blocks

		int ___outbound_blocks[1] = {9};

		ArrayCopy(__outbound_blocks, ___outbound_blocks);



		// IC input parameters

		AlertValue1.Value = 0.0;

		AlertValue2.Value = 0.0;

		AlertValue3.Value = 0.0;

		AlertValue4.Value = 0.0;

		AlertValue5.Value = 0.0;

		AlertValue6.Value = 0.0;

		AlertValue7.Value = 0.0;

		AlertValue8.Value = 0.0;

		AlertValue9.Value = 0.0;

		AlertValue10.Value = 0.0;

	}



	public: /* Custom methods */

	virtual double _AlertValue1_() {return AlertValue1._execute_();}

	virtual double _AlertValue2_() {return AlertValue2._execute_();}

	virtual double _AlertValue3_() {return AlertValue3._execute_();}

	virtual double _AlertValue4_() {return AlertValue4._execute_();}

	virtual double _AlertValue5_() {return AlertValue5._execute_();}

	virtual double _AlertValue6_() {return AlertValue6._execute_();}

	virtual double _AlertValue7_() {return AlertValue7._execute_();}

	virtual double _AlertValue8_() {return AlertValue8._execute_();}

	virtual double _AlertValue9_() {return AlertValue9._execute_();}

	virtual double _AlertValue10_() {return AlertValue10._execute_();}



	public: /* Callback & Run */

	virtual void _callback_(int value) {

		if (value == 1) {

			_blocks_[9].run(7);

		}

	}



	virtual void _beforeExecute_()

	{



		AlertTitle = (string)_externs::inp14_AlertTitle;

		AlsoSendNotification = (bool)_externs::inp14_AlsoSendNotification;

	}

};



// Block 15 (Alert message)

class Block8: public MDL_AlertMessageAdvanced<string,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,string,MDLIC_value_value,double,bool>

{



	public: /* Constructor */

	Block8() {

		__block_number = 8;

		__block_user_number = "15";

		_beforeExecuteEnabled = true;



		// Fill the list of outbound blocks

		int ___outbound_blocks[1] = {10};

		ArrayCopy(__outbound_blocks, ___outbound_blocks);



		// IC input parameters

		AlertValue1.Value = 0.0;

		AlertValue2.Value = 0.0;

		AlertValue3.Value = 0.0;

		AlertValue4.Value = 0.0;

		AlertValue5.Value = 0.0;

		AlertValue6.Value = 0.0;

		AlertValue7.Value = 0.0;

		AlertValue8.Value = 0.0;

		AlertValue9.Value = 0.0;

		AlertValue10.Value = 0.0;

	}



	public: /* Custom methods */

	virtual double _AlertValue1_() {return AlertValue1._execute_();}

	virtual double _AlertValue2_() {return AlertValue2._execute_();}

	virtual double _AlertValue3_() {return AlertValue3._execute_();}

	virtual double _AlertValue4_() {return AlertValue4._execute_();}

	virtual double _AlertValue5_() {return AlertValue5._execute_();}

	virtual double _AlertValue6_() {return AlertValue6._execute_();}

	virtual double _AlertValue7_() {return AlertValue7._execute_();}

	virtual double _AlertValue8_() {return AlertValue8._execute_();}

	virtual double _AlertValue9_() {return AlertValue9._execute_();}

	virtual double _AlertValue10_() {return AlertValue10._execute_();}



	public: /* Callback & Run */

	virtual void _callback_(int value) {

		if (value == 1) {

			_blocks_[10].run(8);

		}

	}



	virtual void _beforeExecute_()

	{



		AlertTitle = (string)_externs::inp15_AlertTitle;

		AlsoSendNotification = (bool)_externs::inp15_AlsoSendNotification;

	}

};



// Block 16 (Draw Arrow)

class Block9: public MDL_ChartDrawArrow<bool,bool,string,ENUM_OBJECT,int,MDLIC_value_time,datetime,MDLIC_candles_candles,double,int,color,ENUM_LINE_STYLE,int,bool,bool,bool,bool,int,string>

{



	public: /* Constructor */

	Block9() {

		__block_number = 9;

		__block_user_number = "16";

		_beforeExecuteEnabled = true;



		// IC input parameters

		ObjTime1.ModeTime = 3;

		ObjPrice1.iOHLC = "iLow";

		ObjPrice1.CandleID = 1;

		ObjPrice1.TimeStamp = "";

		// Block input parameters

		ObjWidth = 5;

	}



	public: /* Custom methods */

	virtual datetime _ObjTime1_() {return ObjTime1._execute_();}

	virtual double _ObjPrice1_() {

		ObjPrice1.Symbol = CurrentSymbol();

		ObjPrice1.Period = CurrentTimeframe();



		return ObjPrice1._execute_();

	}



	public: /* Callback & Run */

	virtual void _callback_(int value) {

	}



	virtual void _beforeExecute_()

	{



		ObjectType = (ENUM_OBJECT)OBJ_ARROW_UP;

		ObjAnchor = (int)ANCHOR_TOP;

		ObjColor = (color)clrMediumTurquoise;

		ObjStyle = (ENUM_LINE_STYLE)STYLE_SOLID;

	}

};



// Block 17 (Draw Arrow)

class Block10: public MDL_ChartDrawArrow<bool,bool,string,ENUM_OBJECT,int,MDLIC_value_time,datetime,MDLIC_candles_candles,double,int,color,ENUM_LINE_STYLE,int,bool,bool,bool,bool,int,string>

{



	public: /* Constructor */

	Block10() {

		__block_number = 10;

		__block_user_number = "17";

		_beforeExecuteEnabled = true;



		// IC input parameters

		ObjTime1.ModeTime = 3;

		ObjPrice1.iOHLC = "iHigh";

		ObjPrice1.CandleID = 1;

		ObjPrice1.TimeStamp = "";

		// Block input parameters

		ObjWidth = 5;

	}



	public: /* Custom methods */

	virtual datetime _ObjTime1_() {return ObjTime1._execute_();}

	virtual double _ObjPrice1_() {

		ObjPrice1.Symbol = CurrentSymbol();

		ObjPrice1.Period = CurrentTimeframe();



		return ObjPrice1._execute_();

	}



	public: /* Callback & Run */

	virtual void _callback_(int value) {

	}



	virtual void _beforeExecute_()

	{



		ObjectType = (ENUM_OBJECT)OBJ_ARROW_DOWN;

		ObjAnchor = (int)ANCHOR_BOTTOM;

		ObjColor = (color)clrLightCoral;

		ObjStyle = (ENUM_LINE_STYLE)STYLE_SOLID;

	}

};





/************************************************************************************************************************/

// +------------------------------------------------------------------------------------------------------------------+ //

// |                                                   Functions                                                      | //

// |                                 System and Custom functions used in the program                                  | //

// +------------------------------------------------------------------------------------------------------------------+ //

/************************************************************************************************************************/





double AccountBalanceAtStart()

{

	// This function MUST be run once at pogram's start

	static double memory = 0;



	if (memory == 0)

	{

		memory = NormalizeDouble(AccountInfoDouble(ACCOUNT_BALANCE), 2);

	}



	return memory;

}



template<typename T>

int ArraySearch(T &array[], T value)

{

	int index = -1;

	int size  = ArraySize(array);



	for (int i = 0; i < size; i++)

	{

		if (array[i] == value)

		{

			index = i;

			break;

		}  

	}



   return index;

}



template<typename T>

bool ArrayStripKey(T &array[], int key)

{

	int x    = 0;

	int size = ArraySize(array);



	for (int i=0; i<size; i++)

	{

		if (i != key)

		{

			array[x] = array[i];

			x++;

		}

	}



	if (x < size)

	{

		ArrayResize(array, x);

		

		return true; // stripped

	}



	return false; // not stripped

}



int CheckForTradingError(int error_code=-1, string msg_prefix="")

{

   // return 0 -> no error

   // return 1 -> overcomable error

   // return 2 -> fatal error

   

   int retval=0;

   static int tryouts=0;

   

   //-- error check -----------------------------------------------------

   switch(error_code)

   {

      //-- no error

      case 0:

         retval=0;

         break;

      //-- overcomable errors

      case TRADE_RETCODE_REQUOTE:

      case TRADE_RETCODE_REJECT:

      case TRADE_RETCODE_ERROR:

      case TRADE_RETCODE_TIMEOUT:

      case TRADE_RETCODE_INVALID_VOLUME:

      case TRADE_RETCODE_INVALID_PRICE:

      case TRADE_RETCODE_INVALID_STOPS:

      case TRADE_RETCODE_INVALID_EXPIRATION:

      case TRADE_RETCODE_PRICE_CHANGED:

      case TRADE_RETCODE_PRICE_OFF:

      case TRADE_RETCODE_TOO_MANY_REQUESTS:

      case TRADE_RETCODE_NO_CHANGES:

      case TRADE_RETCODE_CONNECTION:

         retval=1;

         break;

      //-- critical errors

      default:

         retval=2;

         break;

   }

   

   if (error_code > 0)

   {

      string msg = "";

      if (retval == 1)

      {

         StringConcatenate(msg, msg_prefix,": ",ErrorMessage(error_code),". Retrying in 5 seconds..");

         Sleep(500); 

      }

      else if (retval == 2)

      {

         StringConcatenate(msg, msg_prefix,": ",ErrorMessage(error_code));

      }

      Print(msg);

   }

   

   if (retval==0)

   {

      tryouts=0;

   }

   else if (retval==1)

   {

      tryouts++;

      if (tryouts>=10)

      {

         tryouts=0;

         retval=2;

      }

      else

      {

         Print("retry #"+(string)tryouts+" of 10");

      }

   }

   

   return(retval);

}



bool CloseTrade(ulong ticket, ulong deviation = 0, color clr = clrNONE)

{

	while(true)

	{

		bool success = false;



		if (!PositionSelectByTicket(ticket))

		{

			return false;

		}



		string symbol = PositionGetString(POSITION_SYMBOL);

		long magic    = PositionGetInteger(POSITION_MAGIC);

		double volume = PositionGetDouble(POSITION_VOLUME);



		// With some CFD we can open position with the max volume more than once,

		// so we get a position that has volume bigger than the maximum.

		// Then we cannot close that position, because the volume is too high.

		// For that reason here we will close it in parts.

		double max_volume  = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);

		double part_volume = (volume > max_volume) ? max_volume : volume;



		//-- close --------------------------------------------------------

		MqlTradeRequest request;

		MqlTradeResult result;

		MqlTradeCheckResult check_result;

		ZeroMemory(request);

		ZeroMemory(result);

		ZeroMemory(check_result);



		if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)

		{

			//--- prepare request for close BUY position

			request.type  = ORDER_TYPE_SELL;

			request.price = SymbolInfoDouble(symbol, SYMBOL_BID);

		}

		else

		{

			//--- prepare request for close SELL position

			request.type  = ORDER_TYPE_BUY;

			request.price = SymbolInfoDouble(symbol, SYMBOL_ASK);

		}



		request.action    = TRADE_ACTION_DEAL;

		request.symbol    = symbol;

		request.volume    = part_volume;

		request.magic     = magic;

		request.deviation = (int)(deviation * PipValue(symbol));



		// for hedging mode

		request.position  = ticket;



		// filling type

		if (IsFillingTypeAllowed(symbol, SYMBOL_FILLING_FOK))

			request.type_filling = ORDER_FILLING_FOK;

		else if (IsFillingTypeAllowed(symbol, SYMBOL_FILLING_IOC))

			request.type_filling = ORDER_FILLING_IOC;

		else if (IsFillingTypeAllowed(symbol, ORDER_FILLING_RETURN)) // just in case

			request.type_filling = ORDER_FILLING_RETURN;

		else

			request.type_filling = ORDER_FILLING_RETURN;



		success = OrderSend(request, result);



		//-- error check --------------------------------------------------

		if (!success || (result.retcode != TRADE_RETCODE_DONE && result.retcode != TRADE_RETCODE_PLACED && result.retcode != TRADE_RETCODE_DONE_PARTIAL))

		{

			string errmsgpfx = "Closing position/trade error";



			int erraction = CheckForTradingError(result.retcode, errmsgpfx);



			switch(erraction)

			{

				case 0: break;    // no error

				case 1: continue; // overcomable error

				case 2: break;    // fatal error

			}



			return false;

		}

		

		//-- finish work --------------------------------------------------

		if (result.retcode == TRADE_RETCODE_DONE || result.retcode == TRADE_RETCODE_PLACED)

		{

			// we are closing the position in parts?

			if (volume != part_volume)

			{

				continue; // continue the "while" loop, so that the whole volume could be closed

			}



			while (true)

			{

			  	if (MQLInfoInteger(MQL_TESTER) || !PositionSelectByTicket(ticket))

				{

					break;

				}



				Sleep(10);

			}

		}



		if (success == true)

		{

			if (USE_VIRTUAL_STOPS)

			{

				VirtualStopsDriver("clear", ticket);

			}



			expirationWorker.RemoveExpiration(ticket);

		}

		

		break;

	}

	

	OnTrade();



	return true;

}



template<typename DT1, typename DT2>

bool CompareValues(string sign, DT1 v1, DT2 v2)

{

	     if (sign == ">") return(v1 > v2);

	else if (sign == "<") return(v1 < v2);

	else if (sign == ">=") return(v1 >= v2);

	else if (sign == "<=") return(v1 <= v2);

	else if (sign == "==") return(v1 == v2);

	else if (sign == "!=") return(v1 != v2);

	else if (sign == "x>") return(v1 > v2);

	else if (sign == "x<") return(v1 < v2);



	return false;

}



string CurrentSymbol(string symbol = "")

{

   static string memory = "";



	// Set

   if (symbol != "")

	{

		memory = symbol;

	}

	// Get

	else if (memory == "")

	{

		memory = Symbol();

	}



   return memory;

}



ENUM_TIMEFRAMES CurrentTimeframe(ENUM_TIMEFRAMES tf=-1)

{

   static ENUM_TIMEFRAMES memory=0;

   if (tf>=0) {memory=tf;}

   return(memory);

}



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;



	//-- variant A) use the cache for the last used symbol

	if (symbol == last_symbol)

	{

		return last_point;

	}



	//-- variant B) search in the array cache

	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;

			}



			i++;



			if (i >= size)

			{

				i = 0;

			}

			if (i == start_i) {break;}

		}

	}



	//-- variant C) add this symbol to the cache

	i		= size;

	size	= size + 1;



	ArrayResize(symbols, size);

	ArrayResize(points, size);



	symbols[i]	= symbol;

	points[i]	= 0;

	last_symbol	= symbol;

	last_i		= i;



	//-- unserialize rules from FXD_POINT_FORMAT_RULES

	string rules[];

	StringExplode(",", POINT_FORMAT_RULES, rules);



	int rules_count = ArraySize(rules);



	if (rules_count > 0)

	{

		string rule[];



		for (int r = 0; r < rules_count; r++)

		{

			StringExplode("=", rules[r], rule);



			//-- a single rule must contain 2 parts, [0] from and [1] to

			if (ArraySize(rule) != 2) {continue;}



			double from = StringToDouble(rule[0]);

			double to	= StringToDouble(rule[1]);



			//-- "to" must be a positive number, different than 0

			if (to <= 0) {continue;}



			//-- "from" can be a number or a string

			// a) string

			if (from == 0 && StringLen(rule[0]) > 0)

			{

				string s_from = rule[0];

				int pos       = StringFind(s_from, "?");



				if (pos < 0) // ? not found

				{

					if (StringFind(symbol, s_from) == 0) {points[i] = to;}

				}

				else if (pos == 0) // ? is the first symbol => match the second symbol

				{

					if (StringFind(symbol, StringSubstr(s_from, 1), 3) == 3)

					{

						points[i] = to;

					}

				}

				else if (pos > 0) // ? is the second symbol => match the first symbol

				{

					if (StringFind(symbol, StringSubstr(s_from, 0, pos)) == 0)

					{

						points[i] = to;

					}

				}

			}



			// b) number

			if (from == 0) {continue;}



			if (SymbolInfoDouble(symbol, SYMBOL_POINT) == from)

			{

				points[i] = to;

			}

		}

	}



	if (points[i] == 0)

	{

		points[i] = SymbolInfoDouble(symbol, SYMBOL_POINT);

	}



	last_point = points[i];



	return last_point;

}



bool DeleteOrder(ulong ticket, color arrowcolor=clrNONE)

{

   while(true)

   {

      MqlTradeRequest request;

      MqlTradeResult result;

      MqlTradeCheckResult check_result;

      ZeroMemory(request);

      ZeroMemory(result);

      ZeroMemory(check_result);

   

      request.order=ticket;

      request.action=TRADE_ACTION_REMOVE;

      request.comment="Pending order canceled";

   

      if (!OrderCheck(request,check_result))  {

         Print("OrderCheck() failed: "+(string)check_result.comment+" ("+(string)check_result.retcode+")");

         return false;

      }

      

      bool success = OrderSend(request,result);

      

      //-- error check --------------------------------------------------

      if (!success || result.retcode!=TRADE_RETCODE_DONE)

      {

         string errmsgpfx="Delete order error";

         int erraction=CheckForTradingError(result.retcode, errmsgpfx);

         switch(erraction)

         {

            case 0: break;    // no error

            case 1: continue; // overcomable error

            case 2: break;    // fatal error

         }

         return(false);

      }

      

      //-- finish work --------------------------------------------------

      if (result.retcode==TRADE_RETCODE_DONE)

      {

         //== Wait until MT5 updates it's cache

         int w;

         for (w=0; w<5000; w++)

         {

            if (!OrderSelect(ticket)) {break;}

            Sleep(1);

         }

         if (w==5000) {

            Print("Check error: Delete order");  

         }

         if (OrderSelect(ticket)) {

            Print("Something went wrong with the order");

            return false;

         }

      }

		

		if (success==true) {

         if (USE_VIRTUAL_STOPS) {

            VirtualStopsDriver("clear",ticket);

         }

         //RegisterEvent("trade");

         //return(true);

      }

		

      break;

   }

   OnTrade();

   return(true);

}



string DoubleToStr(double d, int dig){return(DoubleToString(d,dig));}



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 custom_point = CustomPoint(Symbol());

   double current_spread = 0;

   if (custom_point > 0) {

      current_spread = (SymbolInfoDouble(Symbol(),SYMBOL_ASK)-SymbolInfoDouble(Symbol(),SYMBOL_BID))/custom_point;

   }

   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);

}



string ErrorMessage(int error_code=-1)

{

	string e = "";

	if (error_code<0) {error_code=GetLastError();}

	



	switch(error_code)

	{

		//--- success

		case 0: return("The operation completed successfully");

		

		//--- Runtime

		case 4001: e = "Unexpected internal error"; break;

		case 4002: e = "Wrong parameter in the inner call of the client terminal function"; break;

		case 4003: e = "Wrong parameter when calling the system function"; break;

		case 4004: e = "Not enough memory to perform the system function"; break;

		case 4005: e = "The structure contains objects of strings and/or dynamic arrays and/or structure of such objects and/or classes"; break;

		case 4006: e = "Array of a wrong type, wrong size, or a damaged object of a dynamic array"; break;

		case 4007: e = "Not enough memory for the relocation of an array, or an attempt to change the size of a static array"; break;

		case 4008: e = "Not enough memory for the relocation of string"; break;

		case 4009: e = "Not initialized string"; break;

		case 4010: e = "Invalid date and/or time"; break;

		case 4011: e = "Requested array size exceeds 2 GB"; break;

		case 4012: e = "Wrong pointer"; break;

		case 4013: e = "Wrong type of pointer"; break;

		case 4014: e = "System function is not allowed to call"; break;

		case 4015: e = "The names of the dynamic and the static resource match"; break;

		case 4016: e = "Resource with this name has not been found in EX5"; break;

		case 4017: e = "Unsupported resource type or its size exceeds 16 Mb"; break;

		case 4018: e = "The resource name exceeds 63 characters"; break;

		

		//-- Charts

		case 4101: e = "Wrong chart ID"; break;

		case 4102: e = "Chart does not respond"; break;

		case 4103: e = "Chart not found"; break;

		case 4104: e = "No Expert Advisor in the chart that could handle the event"; break;

		case 4105: e = "Chart opening error"; break;

		case 4106: e = "Failed to change chart symbol and period"; break;

		case 4107: e = "Wrong parameter for timer"; break;

		case 4108: e = "Failed to create timer"; break;

		case 4109: e = "Wrong chart property ID"; break;

		case 4110: e = "Error creating screenshots"; break;

		case 4111: e = "Error navigating through chart"; break;

		case 4112: e = "Error applying template"; break;

		case 4113: e = "Subwindow containing the indicator was not found"; break;

		case 4114: e = "Error adding an indicator to chart"; break;

		case 4115: e = "Error deleting an indicator from the chart"; break;

		case 4116: e = "Indicator not found on the specified chart"; break;



		//-- Graphical Objects

		case 4201: e = "Error working with a graphical object"; break;

		case 4202: e = "Graphical object was not found"; break;

		case 4203: e = "Wrong ID of a graphical object property"; break;

		case 4204: e = "Unable to get date corresponding to the value"; break;

		case 4205: e = "Unable to get value corresponding to the date"; break;



		//-- Market Info

		case 4301: e = "Unknown symbol"; break;

		case 4302: e = "Symbol is not selected in MarketWatch"; break;

		case 4303: e = "Wrong identifier of a symbol property"; break;

		case 4304: e = "Time of the last tick is not known (no ticks)"; break;

		case 4305: e = "Error adding or deleting a symbol in MarketWatch"; break;



		//-- History Access

		case 4401: e = "Requested history not found"; break;

		case 4402: e = "Wrong ID of the history property"; break;



		//-- Global Variables

		case 4501: e = "Global variable of the client terminal is not found"; break;

		case 4502: e = "Global variable of the client terminal with the same name already exists"; break;

		case 4510: e = "Email sending failed"; break;

		case 4511: e = "Sound playing failed"; break;

		case 4512: e = "Wrong identifier of the program property"; break;

		case 4513: e = "Wrong identifier of the terminal property"; break;

		case 4514: e = "File sending via ftp failed"; break;

		case 4515: e = "Failed to send a notification"; break;

		case 4516: e = "Invalid parameter for sending a notification - an empty string or NULL has been passed to the SendNotification() function"; break;

		case 4517: e = "Wrong settings of notifications in the terminal (ID is not specified or permission is not set)"; break;

		case 4518: e = "Too frequent sending of notifications"; break;



		//-- Custom Indicator Buffers

		case 4601: e = "Not enough memory for the distribution of indicator buffers"; break;

		case 4602: e = "Wrong indicator buffer index"; break;



		//-- Custom Indicator Properties

		case 4603: e = "Wrong ID of the custom indicator property"; break;



		//-- Account

		case 4701: e = "Wrong account property ID"; break;

		case 4751: e = "Wrong trade property ID"; break;

		case 4752: e = "Trading by Expert Advisors prohibited"; break;

		case 4753: e = "Position not found"; break;

		case 4754: e = "Order not found"; break;

		case 4755: e = "Deal not found"; break;

		case 4756: e = "Trade request sending failed"; break;



		//-- Indicators

		case 4801: e = "Unknown symbol"; break;

		case 4802: e = "Indicator cannot be created"; break;

		case 4803: e = "Not enough memory to add the indicator"; break;

		case 4804: e = "The indicator cannot be applied to another indicator"; break;

		case 4805: e = "Error applying an indicator to chart"; break;

		case 4806: e = "Requested data not found"; break;

		case 4807: e = "Wrong indicator handle"; break;

		case 4808: e = "Wrong number of parameters when creating an indicator"; break;

		case 4809: e = "No parameters when creating an indicator"; break;

		case 4810: e = "The first parameter in the array must be the name of the custom indicator"; break;

		case 4811: e = "Invalid parameter type in the array when creating an indicator"; break;

		case 4812: e = "Wrong index of the requested indicator buffer"; break;



		//-- Depth of Market

		case 4901: e = "Depth Of Market can not be added"; break;

		case 4902: e = "Depth Of Market can not be removed"; break;

		case 4903: e = "The data from Depth Of Market can not be obtained"; break;

		case 4904: e = "Error in subscribing to receive new data from Depth Of Market"; break;



		//-- File Operations

		case 5001: e = "More than 64 files cannot be opened at the same time"; break;

		case 5002: e = "Invalid file name"; break;

		case 5003: e = "Too long file name"; break;

		case 5004: e = "File opening error"; break;

		case 5005: e = "Not enough memory for cache to read"; break;

		case 5006: e = "File deleting error"; break;

		case 5007: e = "A file with this handle was closed, or was not opening at all"; break;

		case 5008: e = "Wrong file handle"; break;

		case 5009: e = "The file must be opened for writing"; break;

		case 5010: e = "The file must be opened for reading"; break;

		case 5011: e = "The file must be opened as a binary one"; break;

		case 5012: e = "The file must be opened as a text"; break;

		case 5013: e = "The file must be opened as a text or CSV"; break;

		case 5014: e = "The file must be opened as CSV"; break;

		case 5015: e = "File reading error"; break;

		case 5016: e = "String size must be specified, because the file is opened as binary"; break;

		case 5017: e = "A text file must be for string arrays, for other arrays - binary"; break;

		case 5018: e = "This is not a file, this is a directory"; break;

		case 5019: e = "File does not exist"; break;

		case 5020: e = "File can not be rewritten"; break;

		case 5021: e = "Wrong directory name"; break;

		case 5022: e = "Directory does not exist"; break;

		case 5023: e = "This is a file, not a directory"; break;

		case 5024: e = "The directory cannot be removed"; break;

		case 5025: e = "Failed to clear the directory (probably one or more files are blocked and removal operation failed)"; break;

		case 5026: e = "Failed to write a resource to a file"; break;



		//-- String Casting

		case 5030: e = "No date in the string"; break;

		case 5031: e = "Wrong date in the string"; break;

		case 5032: e = "Wrong time in the string"; break;

		case 5033: e = "Error converting string to date"; break;

		case 5034: e = "Not enough memory for the string"; break;

		case 5035: e = "The string length is less than expected"; break;

		case 5036: e = "Too large number, more than ULONG_MAX"; break;

		case 5037: e = "Invalid format string"; break;

		case 5038: e = "Amount of format specifiers more than the parameters"; break;

		case 5039: e = "Amount of parameters more than the format specifiers"; break;

		case 5040: e = "Damaged parameter of string type"; break;

		case 5041: e = "Position outside the string"; break;

		case 5042: e = "0 added to the string end, a useless operation"; break;

		case 5043: e = "Unknown data type when converting to a string"; break;

		case 5044: e = "Damaged string object"; break;



		//-- Operations with Arrays

		case 5050: e = "Copying incompatible arrays. String array can be copied only to a string array, and a numeric array - in numeric array only"; break;

		case 5051: e = "The receiving array is declared as AS_SERIES, and it is of insufficient size"; break;

		case 5052: e = "Too small array, the starting position is outside the array"; break;

		case 5053: e = "An array of zero length"; break;

		case 5054: e = "Must be a numeric array"; break;

		case 5055: e = "Must be a one-dimensional array"; break;

		case 5056: e = "Timeseries cannot be used"; break;

		case 5057: e = "Must be an array of type double"; break;

		case 5058: e = "Must be an array of type float"; break;

		case 5059: e = "Must be an array of type long"; break;

		case 5060: e = "Must be an array of type int"; break;

		case 5061: e = "Must be an array of type short"; break;

		case 5062: e = "Must be an array of type char"; break;

		

		//-- Operations with OpenCL

		case 5100: e = "OpenCL functions are not supported on this computer"; break;

		case 5101: e = "Internal error occurred when running OpenCL"; break;

		case 5102: e = "Invalid OpenCL handle"; break;

		case 5103: e = "Error creating the OpenCL context"; break;

		case 5104: e = "Failed to create a run queue in OpenCL"; break;

		case 5105: e = "Error occurred when compiling an OpenCL program"; break;

		case 5106: e = "Too long kernel name (OpenCL kernel)"; break;

		case 5107: e = "Error creating an OpenCL kernel"; break;

		case 5108: e = "Error occurred when setting parameters for the OpenCL kernel"; break;

		case 5109: e = "OpenCL program runtime error"; break;

		case 5110: e = "Invalid size of the OpenCL buffer"; break;

		case 5111: e = "Invalid offset in the OpenCL buffer"; break;

		case 5112: e = "Failed to create an OpenCL buffer"; break;

		

		//-- Operations with WebRequest

		case 5200: e = "Invalid URL"; break;

		case 5201: e = "Failed to connect to specified URL"; break;

		case 5202: e = "Timeout exceeded"; break;

		case 5203: e = "HTTP request failed"; break;



		//-- trading errors

		case 10004: e = "Requote occured"; break;

		case 10006: e = "Order is not accepted by the server"; break;

		case 10007: e = "Request canceled by trader"; break;

		case 10010: e = "Only part of the request was completed"; break;

		case 10011: e = "Request processing error"; break;

		case 10012: e = "Request canceled by timeout"; break;

		case 10013: e = "Invalid request"; break;

		case 10014: e = "Invalid volume"; break;

		case 10015: e = "Invalid price"; break;

		case 10016: e = "Invalid SL or TP"; break;

		case 10017: e = "Trading is disabled"; break;

		case 10018: e = "Market is closed"; break;

		case 10019: e = "Not enough money to trade"; break;

		case 10020: e = "Prices changed"; break;

		case 10021: e = "There are no quotes to process the request"; break;

		case 10022: e = "Invalid expiration date in the order request"; break;

		case 10023: e = "Order state changed"; break;

		case 10024: e = "Too frequent requests"; break;

		case 10025: e = "No changes in request"; break;

		case 10026: e = "Autotrading is disabled by the server"; break;

		case 10027: e = "Autotrading is disabled by the client terminal"; break;

		case 10028: e = "Request locked for processing"; break;

		case 10029: e = "Order or trade frozen"; break;

		case 10030: e = "Invalid order filling type"; break;

		case 10031: e = "No connection with the trade server"; break;

		case 10032: e = "Operation is allowed only for live accounts"; break;

		case 10033: e = "The number of pending orders has reached the limit"; break;

		case 10034: e = "The volume of orders and trades for the symbol has reached the limit"; break;

		case 10035: e = "Incorrect or prohibited order type"; break;

		case 10036: e = "Position with the specified POSITION_IDENTIFIER has already been closed"; break;

		case 10038: e = "A close volume exceeds the current position volume"; break;

		case 10039: e = "A close order already exists for a specified position"; break;

		//-- User-Defined Errors

		case 65536: e = "User defined errors"; break;

		default:	e = "Unknown error";

	}



	StringConcatenate(e, e," (",error_code,")");

	

	return e;

}



class ExpirationWorker

{

private:

	struct CachedItems

	{

		long ticket;

		datetime expiration;

	};



	CachedItems cachedItems[];

	long chartID;

	string chartObjectPrefix;

	string chartObjectSuffix;



	template<typename T>

	void ArrayClone(T &dest[], T &src[])

	{

		int size = ArraySize(src);

		ArrayResize(dest, size);



		for (int i = 0; i < size; i++)

		{

			dest[i] = src[i];

		}

	}



	void InitialDiscovery()

	{

		ArrayResize(cachedItems, 0);



		int total = PositionsTotal();



		for (int index = 0; index <= total; index++)

		{

			long ticket = GetTicketByIndex(index);



			if (ticket == 0) continue;



			datetime expiration = GetExpirationFromObject(ticket);



			if (expiration > 0)

			{

				SetExpirationInCache(ticket, expiration);

			}

		}

	}



	long GetTicketByIndex(int index)

	{

		return (long)PositionGetTicket(index);

	}



	datetime GetExpirationFromObject(long ticket)

	{

		datetime expiration = (datetime)0;

		

		string objectName = chartObjectPrefix + IntegerToString(ticket) + chartObjectSuffix;



		if (ObjectFind(chartID, objectName) == chartID)

		{

			expiration = (datetime)ObjectGetInteger(chartID, objectName, OBJPROP_TIME);

		}



		return expiration;

	}



	bool RemoveExpirationObject(long ticket)

	{

		bool success      = false;

		string objectName = "";



		objectName = chartObjectPrefix + IntegerToString(ticket) + chartObjectSuffix;

		success    = ObjectDelete(chartID, objectName);



		return success;

	}



	void RemoveExpirationFromCache(long ticket)

	{

		int size = ArraySize(cachedItems);

		CachedItems newItems[];

		int newSize = 0;

		bool itemRemoved = false;



		for (int i = 0; i < size; i++)

		{

			if (cachedItems[i].ticket == ticket)

			{

				itemRemoved = true;

			}

			else

			{

				newSize++;

				ArrayResize(newItems, newSize);

				newItems[newSize - 1].ticket     = cachedItems[i].ticket;

				newItems[newSize - 1].expiration = cachedItems[i].expiration;

			}

		}



		if (itemRemoved) ArrayClone(cachedItems, newItems);

	}



	void SetExpirationInCache(long ticket, datetime expiration)

	{

		bool alreadyExists = false;

		int size           = ArraySize(cachedItems);



		for (int i = 0; i < size; i++)

		{

			if (cachedItems[i].ticket == ticket)

			{

				cachedItems[i].expiration = expiration;

				alreadyExists = true;

				break;

			}

		}



		if (alreadyExists == false)

		{

			ArrayResize(cachedItems, size + 1);

			cachedItems[size].ticket     = ticket;

			cachedItems[size].expiration = expiration;

		}

	}



	bool SetExpirationInObject(long ticket, datetime expiration)

	{

		if (!PositionSelectByTicket(ticket)) return false;



		string objectName = chartObjectPrefix + IntegerToString(ticket) + chartObjectSuffix;

		double price      = OrderOpenPrice();



		if (ObjectFind(chartID, objectName) == chartID)

		{

			ObjectSetInteger(chartID, objectName, OBJPROP_TIME, expiration);

			ObjectSetDouble(chartID, objectName, OBJPROP_PRICE, price);

		}

		else

		{

			ObjectCreate(chartID, objectName, OBJ_ARROW, 0, expiration, price);

		}



		ObjectSetInteger(chartID, objectName, OBJPROP_ARROWCODE, 77);

		ObjectSetInteger(chartID, objectName, OBJPROP_HIDDEN, true);

		ObjectSetInteger(chartID, objectName, OBJPROP_ANCHOR, ANCHOR_TOP);

		ObjectSetInteger(chartID, objectName, OBJPROP_COLOR, clrRed);

		ObjectSetInteger(chartID, objectName, OBJPROP_SELECTABLE, false);

		ObjectSetInteger(chartID, objectName, OBJPROP_TIMEFRAMES, OBJ_NO_PERIODS);

		ObjectSetString(chartID, objectName, OBJPROP_TEXT, TimeToString(expiration));



		return true;

	}

	

	bool TradeExists(long ticket)

	{

		bool exists  = false;



		for (int i = 0; i < PositionsTotal(); i++)

		{

			long positionTicket = (long)PositionGetTicket(i);



			if (!positionTicket) continue;



			if (positionTicket == ticket)

			{

				exists = true;

				break;

			}

		}



		return exists;

	}



public:

	// Default constructor

	ExpirationWorker()

	{

		chartID           = 0;

		chartObjectPrefix = "#";

		chartObjectSuffix = " Expiration Marker";



		InitialDiscovery();

	}



	void SetExpiration(long ticket, datetime expiration)

	{

		if (expiration <= 0)

		{

			RemoveExpiration(ticket);

		}

		else

		{

			SetExpirationInObject(ticket, expiration);

			SetExpirationInCache(ticket, expiration);

		}

	}



	datetime GetExpiration(long ticket)

	{

		datetime expiration = (datetime)0;

		int size            = ArraySize(cachedItems);



		for (int i = 0; i < size; i++)

		{

			if (cachedItems[i].ticket == ticket)

			{

				expiration = cachedItems[i].expiration;

				break;

			}

		}



		return expiration;

	}



	void RemoveExpiration(long ticket)

	{

		RemoveExpirationObject(ticket);

		RemoveExpirationFromCache(ticket);

	}



	void Run()

	{

		int count = ArraySize(cachedItems);



		if (count > 0)

		{

			datetime timeNow = TimeCurrent();



			for (int i = 0; i < count; i++)

			{

				if (timeNow >= cachedItems[i].expiration)

				{

					long ticket           = cachedItems[i].ticket;

					bool removeExpiration = false;



					if (TradeExists(ticket))

					{

						if (CloseTrade(ticket))

						{

							Print("close #", ticket, " by expiration");

							removeExpiration = true;

						}

					}

					else

					{

						removeExpiration = true;

					}



					if (removeExpiration)

					{

						RemoveExpiration(ticket);



						// Removing expiration causes change in the size of the cache,

						// so reset of the size and one step back of the index is needed

						count = ArraySize(cachedItems);

						i--;

					}

				}

			}

		}

	}

};



ExpirationWorker expirationWorker;



void HistoryTradesTotalReset()

{

	if (SelectedHistoryToTime() > 0 || SelectedHistoryFromTime() > 0) {

		HistorySelect(SelectedHistoryFromTime(), SelectedHistoryToTime());

	}

}



bool IsFillingTypeAllowed(string symbol,int fill_type)

{

//--- Obtain the value of the property that describes allowed filling modes

   int filling=(int)SymbolInfoInteger(symbol,SYMBOL_FILLING_MODE);

//--- Return true, if mode fill_type is allowed

   return((filling & fill_type)==fill_type);

}



bool LoadPendingOrder(long ticket)

{

	bool success = false;



   if (OrderSelect(ticket))

	{

		// The order could be from any type, so check the type

		// and allow only true pending orders.

		ENUM_ORDER_TYPE type = (ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE);



		if (

			   type == ORDER_TYPE_BUY_LIMIT

			|| type == ORDER_TYPE_SELL_LIMIT

			|| type == ORDER_TYPE_BUY_STOP

			|| type == ORDER_TYPE_SELL_STOP

		) {

			LoadedType(2);

			OrderTicket(ticket);

			success = true;

		}

	}



   return success;

}



bool LoadPosition(ulong ticket)

{

   bool success = PositionSelectByTicket(ticket);



   if (success) {

		LoadedType(1);

		OrderTicket(ticket);

	}



   return success;

}



int LoadedType(int type = 0)

{

	// 1 - position

	// 2 - pending order

	// 3 - history position

	// 4 - history pending order



	static int memory;



	if (type > 0) {memory = type;}



	return memory;

}



int OCODriver()

{

	static long last_known_ticket = 0;

	static long orders1[];

	static long orders2[];

	int i, size;



	int total = OrdersTotal();



	for (int pos=total-1; pos>=0; pos--)

	{

		if (LoadPendingOrder(OrderGetTicket(pos)))

		{

			long 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() <= ORDER_TYPE_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 = size - 1; i >= 0; i--)

	{

		if (LoadPendingOrder(orders1[i]) == false || OrderType() <= ORDER_TYPE_SELL)

		{

			if (LoadPendingOrder(orders2[i])) {

				if (DeleteOrder(orders2[i]))

				{

					dbremove = true;

				}

			}

			else {

				dbremove = true;

			}

			

			if (dbremove == true)

			{

				ArrayStripKey(orders1, i);

				ArrayStripKey(orders2, i);

			}

		}

	}



	size = ArraySize(orders2);

	dbremove = false;

	for (i=size-1; i>=0; i--)

	{

		if (LoadPendingOrder(orders2[i]) == false || OrderType() <= ORDER_TYPE_SELL)

		{

			if (LoadPendingOrder(orders1[i])) {

				if (DeleteOrder(orders1[i]))

				{

					dbremove = true;

				}

			}

			else {

				dbremove = true;

			}

			

			if (dbremove == true)

			{

				ArrayStripKey(orders1, i);

				ArrayStripKey(orders2, i);

			}

		}

	}



	return true;

}



bool OnTimerSet(double seconds)

{

   if (seconds<=0) {

      EventKillTimer();

   }

   else if (seconds < 1) {

      return (EventSetMillisecondTimer((int)(seconds*1000)));  

   }

   else {

      return (EventSetTimer((int)seconds));

   }

   

   return true;

}



class OnTradeEventDetector

{

private:

	//--- structures

	struct EventValues

	{

		// special fields

		string   reason,

		         detail;



		// order related fields

		long     magic,

		         ticket;

		int      type;

		datetime timeClose,

		         timeOpen,

		         timeExpiration;

		double   commission,

		         priceOpen,

		         priceClose,

		         profit,

		         stopLoss,

		         swap,

		         takeProfit,

		         volume;

		string   comment,

		         symbol;

	};



	struct Position

	{

		ENUM_POSITION_TYPE type;

		ENUM_POSITION_REASON reason;

		long     positionId,

		         magic,

		         ticket,

		         timeMs,

		         timeUpdateMs;

		datetime time,

					timeExpiration,

		         timeUpdate;

		double   priceCurrent,

		         priceOpen,

		         profit,

		         stopLoss,

		         swap,

		         takeProfit,

		         volume;

		string   externalId,

		         comment,

		         symbol;

	};



	struct PendingOrder

	{

		ENUM_ORDER_TYPE type;

		ENUM_ORDER_STATE state;

		ENUM_ORDER_TYPE_FILLING typeFilling;

		ENUM_ORDER_TYPE_TIME typeTime;

		ENUM_ORDER_REASON reason;

		long     magic,

		         positionId,

		         positionById,

		         ticket,

		         timeSetupMs,

		         timeDoneMs;

		datetime timeDone,

		         timeExpiration,

		         timeSetup;

		double   priceCurrent,

		         priceOpen,

		         priceStopLimit,

		         stopLoss,

		         takeProfit,

		         volume,

		         volumeInitial;

		string   externalId,

		         comment,

		         symbol;

	};

	

	struct PositionExpirationTimes

	{

		long ticket;

		datetime timeExpiration;

	};



	//--- variables and arrays

	bool debug;



	int eventValuesQueueIndex;

	EventValues eventValues[];



	PendingOrder previousPendingOrders[];

	PendingOrder pendingOrders[];



	Position previousPositions[];

	Position positions[];



	PositionExpirationTimes positionExpirationTimes[];



	//--- methods



	/**

	* Like ArrayCopy(), but for any type.

	*/

	template<typename T>

	void CopyList(T &dest[], T &src[])

	{

		int size = ArraySize(src);

		ArrayResize(dest, size);



		for (int i = 0; i < size; i++)

		{

			dest[i] = src[i];

		}

	}



	/**

	* Overloaded method 1 of 2

	*/

	int MakeListOf(PendingOrder &list[])

	{

		ArrayResize(list, 0);



		int count        = OrdersTotal();

		int howManyAdded = 0;



		for (int index = 0; index < count; index++)

		{

			if (OrderGetTicket(index) <= 0) continue;



			howManyAdded++;

			ArrayResize(list, howManyAdded);

			int i = howManyAdded - 1;



			// enum types

			list[i].type        = (ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE);

			list[i].state       = (ENUM_ORDER_STATE)OrderGetInteger(ORDER_STATE);

			list[i].typeFilling = (ENUM_ORDER_TYPE_FILLING)OrderGetInteger(ORDER_TYPE_FILLING);

			list[i].typeTime    = (ENUM_ORDER_TYPE_TIME)OrderGetInteger(ORDER_TYPE_TIME);

			list[i].reason      = (ENUM_ORDER_REASON)OrderGetInteger(ORDER_REASON);



			// long

			list[i].magic        = (long)OrderGetInteger(ORDER_MAGIC);

			list[i].positionId   = (long)OrderGetInteger(ORDER_POSITION_ID);

			list[i].positionById = (long)OrderGetInteger(ORDER_POSITION_BY_ID);

			list[i].ticket       = (long)OrderGetInteger(ORDER_TICKET);

			list[i].timeSetupMs  = (long)OrderGetInteger(ORDER_TIME_SETUP_MSC);

			list[i].timeDoneMs   = (long)OrderGetInteger(ORDER_TIME_DONE_MSC);



			// datetime

			list[i].timeDone       = (datetime)OrderGetInteger(ORDER_TIME_DONE);

			list[i].timeExpiration = (datetime)OrderGetInteger(ORDER_TIME_EXPIRATION);

			list[i].timeSetup      = (datetime)OrderGetInteger(ORDER_TIME_SETUP);



			// double

			list[i].priceCurrent   = OrderGetDouble(ORDER_PRICE_CURRENT);

			list[i].priceOpen      = OrderGetDouble(ORDER_PRICE_OPEN);

			list[i].priceStopLimit = OrderGetDouble(ORDER_PRICE_STOPLIMIT);

			list[i].stopLoss       = OrderGetDouble(ORDER_SL);

			list[i].takeProfit     = OrderGetDouble(ORDER_TP);

			list[i].volume         = OrderGetDouble(ORDER_VOLUME_CURRENT);

			list[i].volumeInitial  = OrderGetDouble(ORDER_VOLUME_INITIAL);



			// string

			list[i].externalId = OrderGetString(ORDER_EXTERNAL_ID);

			list[i].comment    = OrderGetString(ORDER_COMMENT);

			list[i].symbol     = OrderGetString(ORDER_SYMBOL);

		}



		return howManyAdded;

	}



	/**

	* Overloaded method 2 of 2

	*/

	int MakeListOf(Position &list[])

	{

		ArrayResize(list, 0);



		int count        = PositionsTotal();

		int howManyAdded = 0;



		for (int index = 0; index < count; index++)

		{

			if (PositionGetTicket(index) <= 0) continue;



			howManyAdded++;

			ArrayResize(list, howManyAdded);

			int i = howManyAdded - 1;



			// enum types

			list[i].type   = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

			list[i].reason = (ENUM_POSITION_REASON)PositionGetInteger(POSITION_REASON);



			// long

			list[i].positionId   = (long)PositionGetInteger(POSITION_IDENTIFIER);

			list[i].magic        = (long)PositionGetInteger(POSITION_MAGIC);

			list[i].ticket       = (long)PositionGetInteger(POSITION_TICKET);

			list[i].timeMs       = (long)PositionGetInteger(POSITION_TIME_MSC);

			list[i].timeUpdateMs = (long)PositionGetInteger(POSITION_TIME_UPDATE_MSC);



			// datetime

			list[i].time           = (datetime)PositionGetInteger(POSITION_TIME);

			list[i].timeExpiration = (datetime)0;

			list[i].timeUpdate     = (datetime)PositionGetInteger(POSITION_TIME_UPDATE);



			// double

			list[i].priceCurrent = PositionGetDouble(POSITION_PRICE_CURRENT);

			list[i].priceOpen    = PositionGetDouble(POSITION_PRICE_OPEN);

			list[i].profit       = PositionGetDouble(POSITION_PROFIT);

			list[i].stopLoss     = PositionGetDouble(POSITION_SL);

			list[i].swap         = PositionGetDouble(POSITION_SWAP);

			list[i].takeProfit   = PositionGetDouble(POSITION_TP);

			list[i].volume       = PositionGetDouble(POSITION_VOLUME);



			// string

			list[i].externalId = PositionGetString(POSITION_EXTERNAL_ID);

			list[i].comment    = PositionGetString(POSITION_COMMENT);

			list[i].symbol     = PositionGetString(POSITION_SYMBOL);



			// extract expiration

			list[i].timeExpiration = expirationWorker.GetExpiration(list[i].ticket);



			if (USE_VIRTUAL_STOPS)

			{

				list[i].stopLoss   = VirtualStopsDriver("get sl", list[i].ticket);

				list[i].takeProfit = VirtualStopsDriver("get tp", list[i].ticket);

			}

		}



		return howManyAdded;

	}



	/**

	* This method loops through 2 lists of items and finds a difference. This difference is the event.

	* "Items" are either pending orders or positions.

	*

	* Returns true if an event is detected or false if not.

	*/

	template<typename ITEMS_TYPE> 

	bool DetectEvent(ITEMS_TYPE &previousItems[], ITEMS_TYPE &currentItems[])

	{

		ITEMS_TYPE item;

		string reason   = "";

		string detail   = "";

		int countBefore = ArraySize(previousItems);

		int countNow    = ArraySize(currentItems);



		// New

		if (countBefore < countNow)

		{

			item   = currentItems[countNow - 1];

			reason = "new";

		}

		// Gone

		else if (countBefore > countNow)

		{

			item   = FindMissingItem(previousItems, currentItems);

			reason = "close";

		}

		// Same => check for modifications

		else if (countBefore == countNow && countNow > 0)

		{

			int count = ArraySize(currentItems);



			for (int index = 0; index < count; index++)

			{

				item = currentItems[index];

				ITEMS_TYPE previous = previousItems[index];

				ITEMS_TYPE current  = currentItems[index];



				if (previous.ticket != current.ticket)

				{

					// Type => volume modified

					if (previous.positionId == current.positionId)

					{

						reason = "reverse";

					}

					else

					{

						Print("Positions order mismatch");

					}

					

					break;

				}



				if (previous.volume != current.volume)

				{

					// Volume increment

					if (previous.volume < current.volume)

					{

						reason = "increment";



						break;

					}

					// Volume decrement

					else

					{

						reason = "decrement";



						break;

					}

				}



				// SL & TP modified

				if (

					   previous.stopLoss != current.stopLoss

					&& previous.takeProfit != current.takeProfit

				) {

					reason = "modify";

					detail = "sltp";



					break;

				}

				// SL modified

				else if (previous.stopLoss != current.stopLoss)

				{

					reason = "modify";

					detail = "sl";



					break;

				}

				// TP modified

				else if (previous.takeProfit != current.takeProfit)

				{

					reason = "modify";

					detail = "tp";



					break;

				}

				

				if (previous.timeExpiration != current.timeExpiration)

				{

					reason = "modify";

					detail = "expiration";



					break;

				}

			}

		}



		if (reason == "")

		{

			return false;

		}



		UpdateValues(item, reason, detail);



		return true;

	}



	/**

	* From the list of previous orders or positions, find the item that is missing

	* in the list of current orders or positions.

	*

	* Return the ticket number or 0 if nothing is found.

	*/

	template<typename T> 

	T FindMissingItem(T &previous[], T &current[])

	{

		int previousCount = ArraySize(previous);

		int currentCount  = ArraySize(current);

		T item;



		long ticket = 0;



		for (int i = 0; i < previousCount; i++)

		{

			bool found = false;



			for (int j = 0; j < currentCount; j++)

			{

				if (previous[i].ticket == current[j].ticket)

				{

					found = true;

					break;

				}

			}



			if (found == false)

			{

				item = previous[i];

				break;

			}

		}



		return item;

	}



	/**

	* Overloaded method 1 of 2

	*/

	void UpdateValues(Position &item, string reason, string detail)

	{

		long ticket        = item.ticket;

		datetime timeOpen  = item.time;

		datetime timeClose = (datetime)0;

		double priceOpen   = item.priceOpen;

		double priceClose  = item.priceCurrent;

		double profit      = item.profit;

		double swap        = item.swap;

		double commission  = 0.0;

		double volume      = item.volume;



		if (reason == "close" || reason == "decrement")

		{

			if (HistorySelectByPosition(item.positionId))

			{

				int total = HistoryDealsTotal();



				if (total > 0)

				{

					long firstTicket = (long)HistoryDealGetTicket(0);

					long lastTicket  = (long)HistoryDealGetTicket(total - 1);



					// Ticket is the ticket of the previous deal, the one before the last one

					ticket = (long)HistoryDealGetTicket(total - 2);



					// Open Time and Open Price - get them from the very first deal

					priceOpen = HistoryDealGetDouble(firstTicket, DEAL_PRICE);

					timeOpen  = (datetime)HistoryDealGetInteger(firstTicket, DEAL_TIME);



					// Close Time - get it from the very last deal

					timeClose  = (datetime)HistoryDealGetInteger(lastTicket, DEAL_TIME);

					priceClose = HistoryDealGetDouble(lastTicket, DEAL_PRICE);



					profit     = HistoryDealGetDouble(lastTicket, DEAL_PROFIT);

					swap       = HistoryDealGetDouble(lastTicket, DEAL_SWAP);

					commission = HistoryDealGetDouble(lastTicket, DEAL_COMMISSION);



					volume = HistoryDealGetDouble(lastTicket, DEAL_VOLUME);



					// Find why the position has been closed

					if (detail == "")

					{

						if (

							item.timeExpiration > 0

							&& item.timeExpiration <= timeClose

						) {

							detail = "expiration";

						}

					}



					if (detail == "")

					{

						ENUM_DEAL_REASON dealReason = (ENUM_DEAL_REASON)HistoryDealGetInteger(lastTicket, DEAL_REASON);

	

						switch (dealReason)

						{

							case DEAL_REASON_SL: detail = "sl"; break;

							case DEAL_REASON_TP: detail = "tp"; break;

							case DEAL_REASON_SO: detail = "so"; break;

						}

					}

				}

			}

		}



		int i = eventValuesQueueIndex;



		eventValues[i].reason = reason;

		eventValues[i].detail = detail;



		eventValues[i].priceClose     = priceClose;

		eventValues[i].timeClose      = timeClose;

		eventValues[i].comment        = item.comment;

		eventValues[i].commission     = commission;

		eventValues[i].timeExpiration = item.timeExpiration;

		eventValues[i].volume         = volume;

		eventValues[i].magic          = item.magic;

		eventValues[i].priceOpen      = priceOpen;

		eventValues[i].timeOpen       = timeOpen;

		eventValues[i].profit         = profit;

		eventValues[i].stopLoss       = item.stopLoss;

		eventValues[i].swap           = swap;

		eventValues[i].symbol         = item.symbol;

		eventValues[i].takeProfit     = item.takeProfit;

		eventValues[i].ticket         = ticket;

		eventValues[i].type           = item.type;



		if (debug)

		{

			PrintUpdatedValues();

		}

	}



	/**

	* Overloaded method 2 of 2

	*/

	void UpdateValues(PendingOrder &item, string reason, string detail)

	{

		datetime timeExpiration = item.timeExpiration;



		// When the lifetime of the order is ORDER_TIME_DAY,

		// the expiration (ORDER_TIME_EXPIRATION) equals to the time of opening.

		// Here we fix this.

		if (item.typeTime == ORDER_TIME_DAY)

		{

			timeExpiration = (datetime)(MathFloor(((double)item.timeSetup + 86400.0) / 86400.0) * 86400.0);

		}



		int i = eventValuesQueueIndex;



		eventValues[i].reason = reason;

		eventValues[i].detail = detail;



		eventValues[i].priceClose     = item.priceCurrent;

		eventValues[i].timeClose      = item.timeDone;

		eventValues[i].comment        = item.comment;

		eventValues[i].commission     = 0.0;

		eventValues[i].timeExpiration = timeExpiration;

		eventValues[i].volume         = item.volume;

		eventValues[i].magic          = item.magic;

		eventValues[i].priceOpen      = item.priceOpen;

		eventValues[i].timeOpen       = item.timeSetup;

		eventValues[i].profit         = 0.0;

		eventValues[i].stopLoss       = item.stopLoss;

		eventValues[i].swap           = 0.0;

		eventValues[i].symbol         = item.symbol;

		eventValues[i].takeProfit     = item.takeProfit;

		eventValues[i].ticket         = item.ticket;

		eventValues[i].type           = item.type;



		if (debug)

		{

			PrintUpdatedValues();

		}

	}



	void PrintUpdatedValues()

	{

		Print(

			" <<<\n",

			" | reason: ", e_Reason(),

			" | detail: ", e_ReasonDetail(),

			" | ticket: ", e_attrTicket(),

			" | type: ", EnumToString((ENUM_ORDER_TYPE)e_attrType()),

			"\n",

			" | openTime : ", e_attrOpenTime(),

			" | openPrice : ", e_attrOpenPrice(),

			"\n",

			" | closeTime: ", e_attrCloseTime(),

			" | closePrice: ", e_attrClosePrice(),

			"\n",

			" | volume: ", e_attrLots(),

			" | sl: ", e_attrStopLoss(),

			" | tp: ", e_attrTakeProfit(),

			" | profit: ", e_attrProfit(),

			" | swap: ", e_attrSwap(),

			" | exp: ", e_attrExpiration(),

			" | comment: ", e_attrComment(),

			"\n >>>"

		);

	}



	int AddEventValues()

	{

		eventValuesQueueIndex++;

		ArrayResize(eventValues, eventValuesQueueIndex + 1);



		return eventValuesQueueIndex;

	}



	int RemoveEventValues()

	{

		if (eventValuesQueueIndex == -1)

		{

			Print("Cannot remove event values, add them first. (in function ", __FUNCTION__, ")");

		}

		else

		{

			eventValuesQueueIndex--;

			ArrayResize(eventValues, eventValuesQueueIndex + 1);

		}



		return eventValuesQueueIndex;

	}



public:

	/**

	* Default constructor

	*/

	OnTradeEventDetector(void)

	{

		debug = false;

		eventValuesQueueIndex = -1;

	};



	bool Start()

	{

		AddEventValues();



		MakeListOf(positions);

		MakeListOf(pendingOrders);



		bool success = false;



		if (!success) success = DetectEvent(previousPositions, positions);



		if (!success) success = DetectEvent(previousPendingOrders, pendingOrders);



		CopyList(previousPositions, positions);

		CopyList(previousPendingOrders, pendingOrders);



		return success;

	}



	void End()

	{

		RemoveEventValues();

	}



	string EventValueReason() {return eventValues[eventValuesQueueIndex].reason;}

	string EventValueDetail() {return eventValues[eventValuesQueueIndex].detail;}



	int EventValueType() {return eventValues[eventValuesQueueIndex].type;}



	datetime EventValueTimeClose()      {return eventValues[eventValuesQueueIndex].timeClose;}

	datetime EventValueTimeOpen()       {return eventValues[eventValuesQueueIndex].timeOpen;}

	datetime EventValueTimeExpiration() {return eventValues[eventValuesQueueIndex].timeExpiration;}



	long EventValueMagic()  {return eventValues[eventValuesQueueIndex].magic;}

	long EventValueTicket() {return eventValues[eventValuesQueueIndex].ticket;}



	double EventValueCommission() {return eventValues[eventValuesQueueIndex].commission;}

	double EventValuePriceOpen()  {return eventValues[eventValuesQueueIndex].priceOpen;}

	double EventValuePriceClose() {return eventValues[eventValuesQueueIndex].priceClose;}

	double EventValueProfit()     {return eventValues[eventValuesQueueIndex].profit;}

	double EventValueStopLoss()   {return eventValues[eventValuesQueueIndex].stopLoss;}

	double EventValueSwap()       {return eventValues[eventValuesQueueIndex].swap;}

	double EventValueTakeProfit() {return eventValues[eventValuesQueueIndex].takeProfit;}

	double EventValueVolume()     {return eventValues[eventValuesQueueIndex].volume;}



	string EventValueComment() {return eventValues[eventValuesQueueIndex].comment;}

	string EventValueSymbol()  {return eventValues[eventValuesQueueIndex].symbol;}

};



OnTradeEventDetector onTradeEventDetector;



datetime OrderCloseTime()

{

	int type = LoadedType();



	if (type == 1)

	{

		return 0;

	}



	if (type == 3)

	{

		ulong dealTicket = OrderTicket();

		ENUM_DEAL_ENTRY dealEntry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(dealTicket, DEAL_ENTRY);

		long positionId = HistoryDealGetInteger(dealTicket, DEAL_POSITION_ID);

		datetime time = (datetime)HistoryDealGetInteger(dealTicket, DEAL_TIME);



		HistorySelectByPosition(positionId);



		// Search for the first OUT deal after this one and get the time from it



		int total = HistoryDealsTotal();



		for (int i = total - 1; i >= 0; i--) {

			ulong ticket = HistoryDealGetTicket(i);



			if (ticket == dealTicket) {

				if (i == total - 1 && PositionSelectByDeal(ticket))

				{

					time = (datetime)0;

				}



				break;

			}



			if (HistoryDealGetInteger(ticket, DEAL_ENTRY) == DEAL_ENTRY_OUT) {

				time = (datetime)HistoryDealGetInteger(ticket, DEAL_TIME);

			}

		}



		HistoryTradesTotalReset();



		return time;

	}



	if (type == 4)

	{

		return (datetime)HistoryOrderGetInteger(OrderTicket(),ORDER_TIME_DONE);

	}

	

	return (datetime)OrderGetInteger(ORDER_TIME_DONE);

}



string OrderComment()

{

	int type = LoadedType();



	if (type == 1) {return PositionGetString(POSITION_COMMENT);}

	if (type == 3) {return HistoryOrderGetString(HistoryDealGetInteger(OrderTicket(), DEAL_POSITION_ID), ORDER_COMMENT);}

	if (type == 4) {return HistoryOrderGetString(OrderTicket(), ORDER_COMMENT);}



	return OrderGetString(ORDER_COMMENT);

}



double OrderOpenPrice()

{

	double op  = 0.0;

	int type   = LoadedType();

	int digits = (int)SymbolInfoInteger(OrderSymbol(), SYMBOL_DIGITS);



	if (type == 1)

	{

		op = PositionGetDouble(POSITION_PRICE_OPEN);

	}

	else if (type == 3)

	{

		// Get the value from the very first deal in the position



		ulong positionId = HistoryDealGetInteger(OrderTicket(), DEAL_POSITION_ID);



		HistorySelectByPosition(positionId);



		ulong ticket = HistoryDealGetTicket(0);



		op = HistoryDealGetDouble(ticket, DEAL_PRICE);



		HistoryTradesTotalReset();

	}

	else if (type == 4)

	{

		op = HistoryOrderGetDouble(OrderTicket(), ORDER_PRICE_OPEN);

	}

   else

   {

   	op = OrderGetDouble(ORDER_PRICE_OPEN);

   }



	return NormalizeDouble(op, digits);

}



string OrderSymbol()

{

	int type = LoadedType();



	if (type == 1) {return PositionGetString(POSITION_SYMBOL);}

	if (type == 3) {return HistoryDealGetString(OrderTicket(),DEAL_SYMBOL);}

	if (type == 4) {return HistoryOrderGetString(OrderTicket(),ORDER_SYMBOL);}



	return OrderGetString(ORDER_SYMBOL);

}



long OrderTicket(long ticket = 0)

{

	static long memory = 0;



	if (ticket > 0) {memory = ticket;}



	return memory;

}



int OrderType()

{

	int type = LoadedType();



	if (type == 1) {return (int)PositionGetInteger(POSITION_TYPE);}

	if (type == 2) {return (int)OrderGetInteger(ORDER_TYPE);}

	if (type == 3)

	{

		ulong dealTicket = OrderTicket();

		long positionId = HistoryDealGetInteger(dealTicket, DEAL_POSITION_ID);



		HistorySelectByPosition(positionId);



		ulong firstDealTicket = HistoryDealGetTicket(0);

		

		int orderType = (int)HistoryDealGetInteger(firstDealTicket, DEAL_TYPE);



		HistoryTradesTotalReset();



		return orderType;

	}

	if (type == 4) {return (int)HistoryOrderGetInteger(OrderTicket(),ORDER_TYPE);}



	return (int)OrderGetInteger(ORDER_TYPE);

}



bool PendingOrderSelectByTicket(ulong ticket)

{

	bool success = OrderSelect(ticket);



	if (success) {

		LoadedType(2);

		OrderTicket(ticket);

	}



	return success;

}



double PipValue(string symbol)

{

	if (symbol == "") symbol = Symbol();



	return CustomPoint(symbol) / SymbolInfoDouble(symbol, SYMBOL_POINT);

}



bool PositionSelectByDeal(ulong dealTicket)

{

	bool success = false;

	long positionId = HistoryDealGetInteger(dealTicket, DEAL_POSITION_ID);

	

	if (positionId)

	{

		int total = PositionsTotal();

		

		for (int i = total - 1; i >= 0; i--)

		{

			if (PositionGetTicket(i))

			{

				if (PositionGetInteger(POSITION_IDENTIFIER) == positionId)

				{

					success = true;



					break;

				}

			}

		}

	}



	return success;

}



int SecondsFromComponents(double days, double hours, double minutes, int seconds)

{

	int retval =

		86400 * (int)MathFloor(days)

		+ 3600 * (int)(MathFloor(hours) + (24 * (days - MathFloor(days))))

		+ 60 * (int)(MathFloor(minutes) + (60 * (hours - MathFloor(hours))))

		+ (int)((double)seconds + (60 * (minutes - MathFloor(minutes))));



	return retval;

}



datetime SelectedHistoryFromTime(datetime setTime = -1)

{

	static datetime time;

	

	if (setTime > -1)

	{

		time = setTime;

	}

	

	return time;

}



datetime SelectedHistoryToTime(datetime setTime = -1)

{

	static datetime time;

	

	if (setTime > -1)

	{

		time = setTime;

	}

	

	return time;

}



int StrToInteger(string value)

{

	return (int)StringToInteger(value);

}



template<typename T>

void StringExplode(string delimiter, string inputString, T &output[])

{

	int begin   = 0;

	int end     = 0;

	int element = 0;

	int length  = StringLen(inputString);

	int length_delimiter = StringLen(delimiter);

	T empty_val  = (typename(T) == "string") ? (T)"" : (T)0;



	if (length > 0)

	{

		while (true)

		{

			end = StringFind(inputString, delimiter, begin);



			ArrayResize(output, element + 1);

			output[element] = empty_val;

	

			if (end != -1)

			{

				if (end > begin)

				{

					output[element] = (T)StringSubstr(inputString, begin, end - begin);

				}

			}

			else

			{

				output[element] = (T)StringSubstr(inputString, begin, length - begin);

				break;

			}

			

			begin = end + 1 + (length_delimiter - 1);

			element++;

		}

	}

	else

	{

		ArrayResize(output, 1);

		output[element] = empty_val;

	}

}



datetime StringToTimeEx(string str, string mode="server")

{

	// mode: server, local, gmt

	int offset = 0;



	if (mode == "server") {offset = 0;}

	else if (mode == "local") {offset = (int)(TimeLocal() - TimeCurrent());}

	else if (mode == "gmt") {offset = (int)(TimeGMT() - TimeCurrent());}



	datetime time = StringToTime(str) - offset;



	return time;

}



double TicksData(string symbol = "", int type = 0, int shift = 0)

{

	static bool collecting_ticks = false;

	static string symbols[];

	static int zero_sid[];

	static double memoryASK[][100];

	static double memoryBID[][100];



	int sid = 0, size = 0, i = 0, id = 0;

	double ask = 0, bid = 0, retval = 0;

	bool exists = false;



	if (ArraySize(symbols) == 0)

	{

		ArrayResize(symbols, 1);

		ArrayResize(zero_sid, 1);

		ArrayResize(memoryASK, 1);

		ArrayResize(memoryBID, 1);



		symbols[0] = _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 (symbol == "") symbol = _Symbol;



	if (type == 0)

	{

		exists = false;

		size   = ArraySize(symbols);



		if (size == 0) {ArrayResize(symbols, 1);}



		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 = SymbolInfoDouble(symbol, SYMBOL_ASK);

			bid = SymbolInfoDouble(symbol, SYMBOL_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 == SYMBOL_ASK)

			{

				return SymbolInfoDouble(symbol, SYMBOL_ASK);

			}

			else if (type == SYMBOL_BID)

			{

				return SymbolInfoDouble(symbol, SYMBOL_BID); 

			}

			else

			{

				double mid = ((SymbolInfoDouble(symbol, SYMBOL_ASK) + SymbolInfoDouble(symbol, SYMBOL_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 == SYMBOL_ASK)

				{

					retval = memoryASK[sid][id];



					if (retval == 0)

					{

						retval = SymbolInfoDouble(symbol, SYMBOL_ASK);

					}

				}

				else if (type == SYMBOL_BID)

				{

					retval = memoryBID[sid][id];



					if (retval == 0)

					{

						retval = SymbolInfoDouble(symbol, SYMBOL_BID);

					}

				}

			}

		}

	}



	return retval;

}



int TicksPerSecond(bool get_max = false, bool set = false)

{

	static datetime time0 = 0;

	static int ticks      = 0;

	static int tps        = 0;

	static int tpsmax     = 0;



	datetime time1 = TimeLocal();



	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;

}



int TimeDay(datetime time)

{

	MqlDateTime tm;

   TimeToStruct(time,tm);

   return(tm.day);

}



int TimeDayOfWeek(datetime time)

{

   MqlDateTime tm;

   TimeToStruct(time,tm);

   return(tm.day_of_week);

}



datetime TimeFromComponents(

	int time_src = 0,

	int    y = 0,

	int    m = 0,

	double d = 0,

	double h = 0,

	double i = 0,

	int    s = 0

) {

	MqlDateTime tm;

	int offset = 0;



	if (time_src == 0) {

		TimeCurrent(tm);

	}

	else if (time_src == 1) {

		TimeLocal(tm); 

		offset = (int)(TimeLocal() - TimeCurrent());

	}

	else if (time_src == 2) {

		TimeGMT(tm);

		offset = (int)(TimeGMT() - TimeCurrent());

	}



	if (y > 0)

	{

		if (y < 100) {y = 2000 + y;}

		tm.year = y;

	}

	if (m > 0) {tm.mon = m;}

	if (d > 0) {tm.day = (int)MathFloor(d);}



	tm.hour = (int)(MathFloor(h) + (24 * (d - MathFloor(d))));

	tm.min  = (int)(MathFloor(i) + (60 * (h - MathFloor(h))));

	tm.sec  = (int)((double)s + (60 * (i - MathFloor(i))));

	

	datetime time = StructToTime(tm) - offset;



	return time;

}



int TimeHour(datetime time)

{

	MqlDateTime tm;

	TimeToStruct(time,tm);



	return tm.hour;

}



int TimeMinute(datetime time)

{

	MqlDateTime tm;

	TimeToStruct(time,tm);

	

	return tm.min;

}



int TimeMonth(datetime time)

{

	MqlDateTime tm;

	TimeToStruct(time,tm);



	return tm.mon;

}



int TimeSeconds(datetime time)

{

	MqlDateTime tm;

	TimeToStruct(time,tm);



	return tm.sec;

}



int TimeYear(datetime time)

{

   MqlDateTime tm;

	TimeToStruct(time,tm);



	return tm.year;

}



bool TradeSelectByTicket(ulong ticket)

{

	if (LoadPosition(ticket) && OrderType() < 2)

	{

		return true;

	}



	return false;

}



double VirtualStopsDriver(

	string command = "",

	ulong ti       = 0,

	double sl      = 0,

	double tp      = 0,

	double slp     = 0,

	double tpp     = 0

)

{

	static bool initialized     = false;

	static string name          = "";

	static string loop_name[2]  = {"sl", "tp"};

	static color  loop_color[2] = {DeepPink, DodgerBlue};

	static double loop_price[2] = {0, 0};

	static ulong mem_to_ti[]; // tickets

	static int mem_to[];      // timeouts

	static bool trade_pass = false;

	int i = 0;



	// Are Virtual Stops even enabled?

	if (!USE_VIRTUAL_STOPS)

	{

		return 0;

	}

	

	if (initialized == false || command == "initialize")

	{

		initialized = true;

	}



	// Listen

	if (command == "" || command == "listen")

	{

		int total     = ObjectsTotal(0, -1, OBJ_HLINE);

		int length    = 0;

		color clr     = clrNONE;

		int sltp      = 0;

		ulong ticket  = 0;

		double level  = 0;

		double askbid = 0;

		int polarity  = 0;

		string symbol = "";



		for (i = total - 1; i >= 0; i--)

		{

			name = ObjectName(0, i, -1, OBJ_HLINE); // for example: #1 sl



			if (StringSubstr(name, 0, 1) != "#")

			{

				continue;

			}



			length = StringLen(name);



			if (length < 5)

			{

				continue;

			}



			clr = (color)ObjectGetInteger(0, name, OBJPROP_COLOR);



			if (clr != loop_color[0] && clr != loop_color[1])

			{

				continue;

			}



			string last_symbols = StringSubstr(name, length-2, 2);



			if (last_symbols == "sl")

			{

				sltp = -1;

			}

			else if (last_symbols == "tp")

			{

				sltp = 1;

			}

			else

			{

				continue;	

			}



			ulong ticket0 = StringToInteger(StringSubstr(name, 1, length - 4));



			// prevent loading the same ticket number twice in a row

			if (ticket0 != ticket)

			{

				ticket = ticket0;



				if (TradeSelectByTicket(ticket))

				{

					symbol     = OrderSymbol();

					polarity   = (OrderType() == 0) ? 1 : -1;

					askbid   = (OrderType() == 0) ? SymbolInfoDouble(symbol, SYMBOL_BID) : SymbolInfoDouble(symbol, SYMBOL_ASK);

					

					trade_pass = true;

				}

				else

				{

					trade_pass = false;

				}

			}



			if (trade_pass)

			{

				level    = ObjectGetDouble(0, name, OBJPROP_PRICE, 0);



				if (level > 0)

				{

					// polarize levels

					double level_p  = polarity * level;

					double askbid_p = polarity * askbid;



					if (

						   (sltp == -1 && (level_p - askbid_p) >= 0) // sl

						|| (sltp == 1 && (askbid_p - level_p) >= 0)  // tp

					)

					{

						//-- Virtual Stops SL Timeout

						if (

							   (VIRTUAL_STOPS_TIMEOUT > 0)

							&& (sltp == -1 && (level_p - askbid_p) >= 0) // sl

						)

						{

							// start timeout?

							int index = ArraySearch(mem_to_ti, ticket);



							if (index < 0)

							{

								int size = ArraySize(mem_to_ti);

								ArrayResize(mem_to_ti, size+1);

								ArrayResize(mem_to, size+1);

								mem_to_ti[size] = ticket;

								mem_to[size]    = (int)TimeLocal();



								Print(

									"#",

									ticket,

									" timeout of ",

									VIRTUAL_STOPS_TIMEOUT,

									" seconds started"

								);



								return 0;

							}

							else

							{

								if (TimeLocal() - mem_to[index] <= VIRTUAL_STOPS_TIMEOUT)

								{

									return 0;

								}

							}

						}



						if (CloseTrade(ticket))

						{

							// check this before deleting the lines

							//OnTradeListener();



							// delete objects

							ObjectDelete(0, "#" + (string)ticket + " sl");

							ObjectDelete(0, "#" + (string)ticket + " tp");

						}

					}

					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 (

					!PendingOrderSelectByTicket(ticket)

				|| OrderCloseTime() > 0 // in case the order has been closed

			)

			{

				ObjectDelete(0, name);

			}

			else

			{

				PendingOrderSelectByTicket(ticket);

			}

		}

	}

	// Get SL or TP

	else if (

		ti > 0

		&& (

			   command == "get sl"

			|| command == "get tp"

		)

	)

	{

		double value = 0;



		name = "#" + IntegerToString(ti) + " " + StringSubstr(command, 4, 2);



		if (ObjectFind(0, name) > -1)

		{

			value = ObjectGetDouble(0, name, OBJPROP_PRICE, 0);

		}



		return value;

	}

	// Set SL and TP

	else if (

		ti > 0

		&& (

			   command == "set"

			|| command == "modify"

			|| command == "clear"

			|| command == "partial"

		)

	)

	{

		loop_price[0] = sl;

		loop_price[1] = tp;



		for (i = 0; i < 2; i++)

		{

			name = "#" + IntegerToString(ti) + " " + loop_name[i];

			

			if (loop_price[i] > 0)

			{

				// 1) create a new line

				if (ObjectFind(0, name) == -1)

				{

						 ObjectCreate(0, name, OBJ_HLINE, 0, 0, loop_price[i]);

					ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);

					ObjectSetInteger(0, name, OBJPROP_COLOR, loop_color[i]);

					ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DOT);

					ObjectSetString(0, name, OBJPROP_TEXT, name + " (virtual)");

				}

				// 2) modify existing line

				else

				{

					ObjectSetDouble(0, name, OBJPROP_PRICE, 0, loop_price[i]);

				}

			}

			else

			{

				// 3) delete existing line

				ObjectDelete(0, name);

			}

		}



		// print message

		if (command == "set" || command == "modify")

		{

			Print(

				command,

				" #",

				IntegerToString(ti),

				": virtual sl ",

				DoubleToStr(sl, (int)SymbolInfoInteger(Symbol(),SYMBOL_DIGITS)),

				" tp ",

				DoubleToStr(tp,(int)SymbolInfoInteger(Symbol(),SYMBOL_DIGITS))

			);

		}



		return 1;

	}



	return 1;

}



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;

}



string e_Reason() {return onTradeEventDetector.EventValueReason();}



string e_ReasonDetail() {return onTradeEventDetector.EventValueDetail();}



double e_attrClosePrice() {return onTradeEventDetector.EventValuePriceClose();}



datetime e_attrCloseTime() {return onTradeEventDetector.EventValueTimeClose();}



string e_attrComment() {return onTradeEventDetector.EventValueComment();}



datetime e_attrExpiration() {return onTradeEventDetector.EventValueTimeExpiration();}



double e_attrLots() {return onTradeEventDetector.EventValueVolume();}



double e_attrOpenPrice() {return onTradeEventDetector.EventValuePriceOpen();}



datetime e_attrOpenTime() {return onTradeEventDetector.EventValueTimeOpen();}



double e_attrProfit() {return onTradeEventDetector.EventValueProfit();}



double e_attrStopLoss() {return onTradeEventDetector.EventValueStopLoss();}



double e_attrSwap() {return onTradeEventDetector.EventValueSwap();}



double e_attrTakeProfit() {return onTradeEventDetector.EventValueTakeProfit();}



long e_attrTicket() {return onTradeEventDetector.EventValueTicket();}



int e_attrType() {return onTradeEventDetector.EventValueType();}



double fxdCustomIndicator(int handle, int mode=0, int shift=0)

{

	static double buffer[1];



	if (handle < 0)

	{

		Print("Error: Indicator not handled. (handle=",handle," | error code=",GetLastError(),")");

		return 0;

	}



	int tryouts = 0;



	while (true)

	{

		if (BarsCalculated(handle) > 0) break;

		else

		{

			tryouts++;



			if (MQLInfoInteger(MQL_TESTER))

			{

				Sleep(10);

			}

			else

			{

				if (tryouts > 100)

				{

					Print("Error: Custom indicator could not load (handle=",handle," | error code=",GetLastError(),")");



					break;

				}



				Sleep(50);

			}

		}

	}



	int success = CopyBuffer(handle,mode,shift,1,buffer);



	if (success < 0)

	{

		Print("Error: Cannot get value from a custom indicator. (handle=",handle," | error code=",GetLastError(),")");

		return 0;

	}



	//ArraySetAsSeries(buffer,true);



	return buffer[0];

}



int iCandleID(string SYMBOL, ENUM_TIMEFRAMES TIMEFRAME, datetime time_stamp)

{

	bool TimeStampPrevDayShift = true;

	int CandleID               = 0;



	// get the time resolution of the desired period, in minutes

	int mins_tf  = TIMEFRAME;

	int mins_tf0 = 0;



	if (TIMEFRAME == PERIOD_CURRENT)

	{

		mins_tf = (int)PeriodSeconds(PERIOD_CURRENT) / 60;

	}



	// get the difference between now and the time we want, in minutes

	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);

	}



	// 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--;



		if (CandleID <= 0) {CandleID = 0; break;}

	}



	return CandleID;

}



double iMACD( 

	string             symbol,

	ENUM_TIMEFRAMES    timeframe,

	int                fast_ema_period,

	int                slow_ema_period,

	int                signal_period,

	ENUM_APPLIED_PRICE applied_price,

	int                mode,

	int                shift

)

{

	int handle = iMACD(symbol, timeframe, fast_ema_period, slow_ema_period, signal_period, applied_price);

	double val = fxdCustomIndicator(handle, mode, shift);



	return NormalizeDouble(val, 6);

}



double iStochastic( 

	string             symbol,

	ENUM_TIMEFRAMES    timeframe,

	int                Kperiod,

	int                Dperiod,

	int                slowing,

	ENUM_MA_METHOD     ma_method,

	ENUM_STO_PRICE     price_field,

	int                mode,

	int                shift

)

{

	int handle = iStochastic(symbol, timeframe, Kperiod, Dperiod, slowing, ma_method, price_field);

	double val = fxdCustomIndicator(handle, mode, shift);



	return NormalizeDouble(val, 2);

}



double toPips(double digits, string symbol)

{

	if (symbol == "") symbol = Symbol();



   return digits / (PipValue(symbol) * SymbolInfoDouble(symbol, SYMBOL_POINT));

}













class FxdWaiting

{

	private:

		int beginning_id;

		ushort bank  [][2][20]; // 2 banks, 20 possible parallel waiting blocks per chain of blocks

		ushort state [][2];     // second dimention values: 0 - count of the blocks put on hold, 1 - current bank id



	public:

		void Initialize(int count)

		{

			ArrayResize(bank, count);

			ArrayResize(state, count);

		}



		bool Run(int id = 0)

		{

			beginning_id = id;



			int range = ArrayRange(state, 0);

			if (range < id+1) {

				ArrayResize(bank, id+1);

				ArrayResize(state, id+1);



				// set values to 0, otherwise they have random values

				for (int ii = range; ii < id+1; ii++)

				{

				   state[ii][0] = 0;

				   state[ii][1] = 0;

				}

			}



			// are there blocks put on hold?

			int count = state[id][0];

			int bank_id = state[id][1];



			// if no block are put on hold -> escape

			if (count == 0) {return false;}

			else

			{

				state[id][0] = 0; // null the count

				state[id][1] = (bank_id) ? 0 : 1; // switch to the other bank

			}



			//== now we will run the blocks put on hold



			for (int i = 0; i < count; i++)

			{

				int block_to_run = bank[id][bank_id][i];

				_blocks_[block_to_run].run();

			}



			return true;

		}



		void Accumulate(int block_id = 0)

		{

			int count   = ++state[beginning_id][0];

			int bank_id = state[beginning_id][1];



			bank[beginning_id][bank_id][count-1] = (ushort)block_id;

		}

};

FxdWaiting fxdWait;







//+------------------------------------------------------------------+

//| END                                                              |

//| Created with fxDreema EA Builder           https://fxdreema.com/ |

//+------------------------------------------------------------------+



/*<fxdreema:eNrtHWtv2zjyrwTZL3dAt9Dbjx4OcJyk7Z0d52J3i90vgizRMS+yqJXkpL5F//sNXxKlSE7SqHm0Wix2ZQ05nBnOi0NS8Ya94V/pUNeHhz6JIuRnmETp4TtvqGvDv/BQgyeTtrCHhyuMwuDwXQpdDo9PTkefJgv6yxkepmSb+Ij+ADymeJl5ySXKxEvn8N1XPNQfjs25hc0YHuoaQ2c8HJ1VR5zNsJkPx2bXYRswbNbDsRl12CyGzW4Jm8mwOQ/HNqidBk5c74HoxATW4OMT0f8GfFYtPq51g2/AZ9fi6wG+r+z9MiT+FbcTm9oJVUVDp4P0mSVlCQkZmA0MHea7zZKEFJE2PBTIz1GCCaNGt+DXycXH2bE7/nRxcXLGqNJhzHMvTafelwXeoFTMhQ5UpMMBH8fDEUooADAssH9FH4GEAKfeMkSAfAk2zNhFXzKUcNsG0/7KOMKBqi2AEqeuv00zspEd+5JXLgUqqF2aoY0YZ0MCFLoCDXA2i3wEbB15jCYdho29xNsgGBowE5IEaVkGMQavk5MJM5T6XogEMCLJxgsl7hRRXBlJFB4oPZmXbdkrQ0wyichqdfgOM5Qgl8DLvHzUr6xJhjM+CpUxJfogRsnBkpMNSAEB41ggBSQhWmUUp2FTrCagIDH9bdkUJTS48XAm+QBJXnsJplOgEAvSINss3mapihjDO9pP58Qi8VOjaGEYPy30SKea5/lXlwnZRsGvPglJIpT5l6WGjD7zvTbVDAGBqf2F/R8eVqAuv94gfLnOVGlQ3ZMa64KSJF5BMZXOEiYNJb+m2Y5LjPfj/rJW5Z0mlQcyV16anUxH0qAM8ToNyU3x2nCENqb4MvLCOQdIL6SDUDaeHyzWCUrXhJszDKe91TTNvJdpPdJ8bB4ZywxhNoEqL9QrVNmgYqtlgUaMEuUVAzXbMFCdD3uMr4/Qq7FQA35MR+PjAyAbgTemxvo3Sj9O13+/01zNXq9krrrdf357hW6/nI61JzRWqzPWJzRWq2Vj3YbhqzZWoP9extrXK7bq/Iy2ajfZqkXfQccJyXnMtc6gT1GAfTajLp5nxF+DumNf6JaKiK7tmMj+HeemB/1tTWbGxWtpyPB2DraCo0tp95pAPB2BPq55a/pzdnziSi8ALJ0n2EenMu2m4povZu5k9vnDx/cfhICnoPdiMLkw+JZ8GeZnvsarrMiTOQnjGTQZLz7Ozgoxc5XxyQaMQI79T8HaxQ8sX/3p5EtBfkLS9AYH2bq0eNlnGo9x9kbJQlTXn89E7vqPizdGZQK4488F1+DuL4pB7FuDOLcG6d0apF8eZFAZpBJU7BaCCnQfE9BiWuV5JRGlSvLeAKKb5cWZYfVexurs9PR4PBp8SxDZEyicLlA8T6D4RxcoukDxYgOF0wWKOwOFpdvlQGHaP3Cg6H9LoKCmpzoy7kkqCPoC6XRU8lS2YGc6ShU/cB9HBcOP4jjEKGD+SjJ9fvFxfOKOJ7P5yf38khhN9USiXVsrgm+WT+6zX5+AHuyp9Xx3kfZyb3drdxuj37m+O11fr7KBYfSsH9j1DZpcH0+9gM2P0oa7XLmNXA64GHtRAGpzu5uZw0qOiAOBlpMvPoqpEotWKvmUuk8xyHCCrlEomWNbul9Qvv9YtBASNTUpoUCF3XLmOtX3cItc9t+a6ZV2+ZuEQ9+edpc0LBpbb+4gumhRYpjSrILaodncT/MjXbJDk1zrXZ0e8OS3Rgd4Dlw//zwbrs4sz4hvi65qzdbj8vo9OfaghUADbqkg9zPO1jia4A3O0u8ddXQqFl2Nwo+v+6uiP9iQa5Qe3DCWDsKcp/21/34pKpmG+WKikuUYT1j+17UuZP28Icukh6NeXcwq8HZB64UGrfzUXRe1WoxaZr9cRzI1+2cNW3pT2LJF1HoPZMaKP6Fkx+L5vXxWahDc9csOTCdlLKgLDJSno+0unSVzFIapcAJLQgsObRYaGKuPP94B45+RWYzAGGZU

oulrOTCpU8IPYpLer9xg2OXETtedl2Eho8F4cHr6lBbSeEjYtsREVM2gVs/h/7+RcLtBTbGZQ+f4f0gouvZW06XSFcALnF6VMr6irwSBOI23tkyEOAyii4+irJKs9CX4iBqA0kaeXWSZgUpZC5mBSVm7M70DLKdUPBceKOynCGd1krHVRsco5AaQ57d0XjebReIFkAIQUl6o2xQ2vfwIqLEXTgiPGwpxfd5gug0zHIe7WTQhaaqevDa0aovzhKxwORXt8TajIKBDlJBwOgaVBiUcJVIvEFhrDYZeCdxEg24aTjOzpmxyARlOkuYa6oX8meM4xUvSiMNg0j4Gv7ZZoiS7Q7B5u4YBDUbRxFuSrb9GCWpG55QbTnCaSc3U3xhvzDfWG/uNU8i6aNrEKxt6jv488lJUM6AuwMVUQG8ThnJKvWunwhDApqEdaZE8CaX5jOpFoDusDWM6rvQjwFPMDXdxXm1zjuO05CyoyuZA3ivfkGCGZdtytivNOHLFdwCmIJSNWnEM99x0DuJWRy2ztG/coNVxVT+2f1238K4QV6V8qQ0DB7vI22C/qECWWt6eeaME3jP3g5qG80lFVJSAsGhWI5FeuaRxBOustEYuA7nXxBqc395vo8JhsHl1zw0IPUbX2Mv3fIRfvudum8Vzu2c4OUGFF+8V3vdSYzpy0PLI91PkHl1z5wsJoPb9YiySOnh/7O3UjLnPXn4g2yStypQiwdE2Q2p7mv0CoIYdTbKT4U0tN4bc6wXKFqJNHlk1utyA1Ee9VCdVjwEybyMXQ5o2LGyDAnll4eNxlQMKm3rJFSp59oHaiT6t6IKiGudZE7KJSQRG+bu4DiJR9CvwKfC5Vhs4lQYgdRVcxU/lX7pGkBOZj8BmoprOlJrMEYg7qJGd6vY1GTjlLKjmZOTeTQIo4+r00wQpBzKuS1C162eErkpAUwFKLcxnS+2Za2NFmnzQWypZAnMh1IKvcExpCsTQMGKWULlQm+nTOhGOY+8SVe4oTHcg4I1I1hVWRklCbsZ0WQSLamFefpgcMVE/cj1tyhJXdbUiCjxNOUNdrHD49csazy+ub1ScPq/0lR2+qPLdcva8yJd7d17X21dga+MapcPKGGfk5nsXBGyloKbJgiJXWCE68Wwpbez8uY1iQo/xehBxZvfWERytXGmzdK2lOoJWriPoD6wjaFpf027dD6GQFfunoZrAalNh8LiKgtlVFLqKQldR6CoKXUWhqyh0FYUftaJgdBWFrqLQVRS6isLrrShYakWBbtAL9+WHyQUKuopCU0Whje++UOZB4j9HSaHPmb1XTWGgV77lZLyQmsJqpT1bTaHxUzE8HNFJH4WwNlrkp6iAsd/BAR2w1wdTlKbgFA7oIkbSySCwtkGhXjmxwyDM3ept5el3JholgoxGgoznIchsJMh8HoKsRoKs5yHIbiTIfh6CnEaCnOchqNdIUO95COo3EtR/HoIGjQQNnowgo+QYtUotRfGM2lORZDDnnpI5ioIzkuEVXSKLFWxRCnr83fsiV1NDCU8dmmmo5kZtfGbLkDSIsDUKrr3IR8F3P82sN6RKmpIqac2pkjh/Lp57ynNfeR4ozyzXyX+0e5CabRiy6L/hYrz7WKhulg9OD75T6qU9OPVarWznKY+F2g9NuAppTwtpd2lWl2Z1aVaXZnVpVpdmtZtm2V2a9WrTLKvyQTxzYPysaVbj1/J0/icw6Ifgl/9FflZ8vz4veKvgTzFMEaqAewx6JnZFlHM1vM9iFxdYjv7lji4uZp/dT+cKZlEdD+SVV7svzAhgtBivt7iBZHYbSC9lA0l78g2kuo5Ps3+khDYe20C12b5InW5Tt8AvVLt+cbW+ouA94UTx7MNkLEwST8Q+h8MlzpXuFEfB0U5MOJYfKajT4qr27zk4d5+/4dGcBXABjCJ/LZwfjZFn4w+zC3cxOy+sf5x7xz7bL5uiAG83i23y55bgFBUN59Ln8a8r/D45ceezCeeOt/isfH/L

LvzWkcdziupBI4oTheC/aGSoOkRdgfNArnbnzH3AQYCietgfzFFXfQDld+0l2Xy7/AxTxqdS+v4WPxYm/jxMK/d4GcHHiXfDfPj3Tmms8j342j02NaNpK/eAl5THg5zJ/fUdzSpvrTn2S0k8eiv7KT/nrvdeQuJhqYnH8ezzWZd6dKlHl3q0mHrQ5w/gNF5n7mHmucfRbLGYTevSD5OlHxPqGMck4fGpyzy+JfPo/bCZh/7smYdlVS4KOYOfMvPgZ/RASBmOLjk/PUmi52f4GrlNKk2RxgmhCYQbyWjZo3qe/1Efj5ahjGrjTKQbDjWAGFrkfgMU1w296HIrqlb0a2//mdj5PR7IbFw/QSLBMSx6wtowf9XgX2Oh2UOtP9QGbweW9kepCxgEXu3u22XjXWLfBW1M5HGpQc+w5FetrnGKQR3cEC8TL9m5+feJSlZIA7FsyUy1qR3VQPDliZsWUQpE5eTfSYsJjjI32QoNNOXfW5Vqt0qoXwiG9G9l6bxzRsQLXf451brGt5trvIPR2KG+x1c+7dsUudc4ybZeCMIj+eH9iBSiU6AsJWQ2IurPA44Cbbjy7GqQ0DYVuJtUvoda08QLguonU9E1JEepK0/P07ghtXqQQ/2dD9NX/rgaA0fUIbhpDJoYuMyHVr8GKJsIl1YA6SUGyFUyOuNrcuMWFwyq950uEy9euyTBQEtxQQBaLEi8IEckYwGBJ57SssCccJI3Fs6cRaV4l0iHwS5CIcCZEALMvQUhFWfwApT6CY4rKKjjxNHV3t7wnl4IUjvmIRHkEGVp/qlvehuM3jhTPy6PZYgWEB4yweEr3iIg22V4B6m2WHIofxn3a5Mjh7YezGHZtedM0Gj19f+oi8Jm

:fxdreema>*/

Comments