////////////////////////////////////////////////////////
//				 	Free Momods Night Scalper					//
//						modded by pip.digger						//
//																		//
//								based on								//
//																		//
//     Momods_Night_Scalper_V3.02_Basic_MMfix         //
//     Coded by Momods @ worldwide-invest.org         //
//                  April 29, 2013                    //
////////////////////////////////////////////////////////

//V1.3 (March 17, 2013) - Added second condition for Fractals signal
//                      - Added MA Slope filter
//                      - Added settings internally
//
//V1.4 (March 23, 2013) - Fixed a bug in displaying Open/Close hours
//                      - No need to add pair suffix
//                      - Added code to generate master magic number for all pairs based on account number
//                      - Faster back tests
//                      - hide EA name in comments from broker (enter your own)
//                      - Option to hide SL/TP from broker.  Highly dangerous if you are not using VPS.
//                      - Now you can see total profit (loss) for each pair on the display
//                      - Revised settings for several pairs based on optimization
//
//V2.0 (March 31, 2013) - Fixed a bug in calculating trading times for friday
//                      - Added BB to be used either as Signal or filter.
//                      - Added trade spacing time filter (When a trade closes in loss, EA will wait x minutes before opening a same type trade).
//                      - Modified settings for EURCAD, EURGBP, and USDCAD.
//V2.1 (March 31, 2013) - Fixed a bug in calculating trade pause
//V2.2 (April 2, 2013)  - Fixed another bug in session display.
//
//V2.21 (April 14, 2013) - Added Max Spread to externals 
//                       - Fixed display bug  
//
//V3.0 (April 21, 2013)  - Added Auto-Timing (EA will determine your broker's GMT Offset automatically).
//                       - Added Daylight Saving Timing (DST) for back testing
//                       - Added maximo's Fractal Level indicator 
//                       - Renamed several parameters to remove any confusion
//                       - Added second option to puase trades on loss based on pips from last loss (good for trading on price charts....renko...range..)
//                       - Added RSI indicator as signal/filter
//V3.01 (April 24, 2013) - Limited Auto timing just to get correct GMT Offset.  Use manual GMT offset for trading.
//V3.02 (April 29, 2013) - Fixed default mode for MA that affected EURUSD settings.
//                       - Changed default max spread=0 which prevented internal settings from being used.
//								 - LAST FREE VERSION BY MOMODS
//
//V3.02_MMfix (May 23, 2013) - Fixed money management to consider account currency and quote currency.
//
//v0.9.0 (May 31, 2013)  - Replaced magic number generator
//								 - Revised EA parameter list
//								 - Corrected MA_Dist signal
//								 - Updated HUD
//                       - HUD now shows in visual backtest
//                       - Speedups for backtesting
//								 - TakeProfit, Friday_Hour, and Risk are now a default parameters, 
//									Risk = 0.0 means use defaults
//								 - Unified Basic and Pro versions
//								 - New PRO parameter section, disable AutoConfig to use manual parameters in PRO section
//v0.9.1 (May 31, 2013)  - Updated trading hours code to account for fractional hours, and DST changes thruout the trading year
//								 - All trading hours are now specified as doubles = fractional hours
//								 - Now allows correct backtests with DST adjusted history data
//								 - Changed parameter UseDST to HistoryUsesDST
//v0.9.2 (Jun 1, 2013)	 - Bugfix for backtesting using HistoryUsesDST
//v0.9.3 (Jun 3, 2013)	 - Fixed to compile with build 500
//								 - Combined and further cleaned up some functions
//v0.9.4 (Jun 4, 2013)	 - Corrected trading hours handling in defaults
//								 - Removed superfluous log messages
//								 - More code cleaning and small speedups
//								 - Changed "HistoryUsesDST" to "AdjustForDST"
//v0.9.5 (Jun 5, 2013)	 - Included ATR filter
//								 - Renamed "OppositFractalDist" to "OppositeFractalDist"
//								 - More code cleaning and small speedups
//v0.9.6 (Jun 6, 2013)	 - 2nd Trade now only opens when trade session is Open
//								 - Removed IsOptimization() calls since they made no difference
//								 - Added 2 new parameters "CloseByActualSpread" and "CloseByMedianSpread"
//									to control behaviour for closing trades under high spread
//								 - Changed Spread handling for open new trades,
//									was: MedianSpread < Max_Spread
//									now: Ask-Bid <= MedianSpread
//								 - More code cleaning and small speedups
//v0.9.7 (Jun 7, 2013)	 - Revised HUD
//								 - Revised open and close signals, may now trigger simultaneously
//								 - Adjusted slippage parameter for 5-digit brokers
//								 - Added 2nd way of determining GMT offset from windows clock
//									EA will now try both and return most plausible value
//								 - Adjusted trading hour defaults and some risk defaults
//v0.9.8 (Jun 13, 2013)	 - EA now tries several times to fetch correct GMT offset if auto detection
//									provides dubious values. Should help with restarts over the weekend.
//								 - Updated HUD to show instrument, Risk setting, and auto config status
//								 - Improved Friday trading rule
//								 - Rollover protection, deactivates new trades xx/yy minutes before/after
//									rollover and shifts SL by SL_ExtraPips
//v0.9.9 (Jun 18, 2013)	 - Added FFCal news filter
//								 - Restructured rollover protection handling for higher speed
//v1.0.pre1 (Jun.21, 2013)	- Corrected IsNewsTime() to actually return a value ;)
//								 	- New defaults
//v1.0.pre2 (Jun.26, 2013)	- Added ATR_MinPips to ATR Filter
//								 	- Added toggle to log slippage (only for market open/close orders, not for hard TP/SL)
//									- Adjusted arrow colors
//								 	- New defaults
//v1.0.pre3 (Jun.28, 2013)	- Changed median spread filter to work for close the same like for opening
//								 	- New defaults
//v1.0.pre4 (Jul.01, 2013)	- Option to log slippage to external csv file
//									- Added gvar to suspend trading globally for all instances of the EA
//									- Moved 2nd trade to PRO section, and made part of defaults
//									- Paramter TradeOnFriday made internal, default = true
//									  (made no sense to stop trading on Friday morning, interim solution)
//v1.0.pre5 (Jul.02, 2013)	- Moved slippage logging to separate function and perform on-demand FileFlush()
//									- Changed Slippage parameter to double, to allow fractional pips on 5-digit brokers
//									- Fixed IsNewsTime() to return correct value ;)
//v1.0.pre6 (Jul.04, 2013)	- Cleaned up close spread check and corrected potential bug in HUD
//									- Bug fix: When turning off news filter during news and while EA was running, 
//									  NewsTime didn't reset and trading would remain permanently suspended...
//									- Changed IsEDT() from lookup table to date algo

#property copyright "Copyright © 2013, Momods, pip.digger"
#property link      "http://worldwide-invest.org/"

#include <WinUser32.mqh>

#import "Kernel32.dll"
int GetTimeZoneInformation(int& TIME_ZONE_INFORMATION[]);
void GetSystemTime(int& SYSTEMTIME[]);
#import

// EA name and version
string	EA_Name= "Free Momods Night Scalper";
string	EA_Version = "1.0.pre6";

// externals
extern string	EA_Configuration			= "==== EA Configuration ====";
extern string	EA_Comment					= "";
extern int		Magic 						= 0;
extern string	MagicKey						= "";
extern string	TimeSettings				= "==== Time settings ====";
extern bool		AutoGMT						= true;
extern int		GMT_Offset					= 0;
extern double	GMT_Open_Hour				= -1.0;
extern double	GMT_Close_Hour				= -1.0;
extern double	GMT_Friday_Hour			= -1.0;
 bool		TradeOnFriday				= true;
extern string	BackTesting					= "==== Backtesting ====";
extern bool		AdjustForDST				= false;
extern string	MoneyManagement			= "==== Money Management ====";
extern double	LotSize						= 0.0;
extern double	Risk							= 0.0;
extern string	TradeSettings				= "==== Trade settings ====";
extern bool		New_Trade					= true;
extern double	Max_Spread					= 0.0;
extern bool		CloseByActualSpread		= true;
extern bool		CloseByMedianSpread		= true;
extern bool		Hide_SL_TP					= false;
extern string	SlipSettings				= "==== Slippage & Log ====";
extern double	Slippage						= 1.0;
extern bool		LogSlippage					= false;
extern bool		LogToSeperateFile			= true;
extern string	PauseLoss					= "==== Pause after loss ====";
extern bool		Trade_Pause_On_Loss		= false;
extern string	Pause_Comment				= "Pause type: 1= Use Minutes, 2= Use Pips";
extern int		Pause_Type					= 1;
extern int		Trade_Pause_Minutes		= 60;
extern double	Trade_Pause_Pips			= 20.0;
extern string	NewsFilter					= "==== News Filter ====";
extern bool		Use_NewsFilter				= false;
extern int		MinsBeforeNews				= 120;	// mins before an event to stay out of trading
extern int		MinsAfterNews				= 30;		// mins after  an event to stay out of trading
extern bool		IncludeHigh					= true;
extern bool		IncludeMedium				= true;
extern bool		IncludeLow					= false;
extern bool		IncludeSpeaks				= true; // news items with "Speaks" in them have different characteristics
extern string	ROProtection				= "==== Rollover Protection ====";
extern bool		RolloverProtection		= false;
extern int		MinsBeforeRollover		= 5;
extern int		MinsAfterRollover			= 5;
extern double	SL_ExtraPips				= 50.0;
extern string	EyeCandy						= "==== Eye Candy ====";
extern bool		Show_Fractal_Levels		= false;
extern string	ProSettings					= "==== PRO Settings ====";
extern bool		AutoConfig					= true;
extern string	STPSL="----------------------";
extern double	TakeProfit					= 60.0;
extern double	StopLoss						= 50.0;
extern string	S2ND="----------------------";
extern bool		Allow_Second_Open_Trade	= false;
extern double	Distance						= 12.0;
extern double	Lot_Factor					= 0.5;
extern string	SCCI="----------------------";
extern bool		Use_CCI						= false;
extern int		CCI_Period					= 10;
extern double	CCI_Entry					= 200;
extern double	CCI_Exit						= 140;
extern string	SWPR="----------------------";
extern bool		Use_WPR						= true;
extern int		WPR_Period					= 10;
extern double	WPR_Entry					= 91;
extern double	WPR_Exit						= 40;
extern string SFractals="----------------------";
extern bool		Use_Fractals				= true;
extern double	MidFractalDist				= 5;
extern double	OppositeFractalDist		= 10;
extern string SATR="----------------------";
extern bool		Use_ATR						= false;
extern int		ATR_Period					= 14;
extern double	ATR_MinPips					= 1;
extern double	ATR_MaxPips					= 11;
extern string SMA="----------------------";
extern bool		Use_MA1						= false;
extern int		MA_Period1					= 75;
 string	Mode1						= "0= Simple, 1= Exponential, 2= Smoothed, 3= Linear Weighted";
 int		MA_Mode1					= 2;
extern bool		Use_MA2						= false;
extern int		MA_Period2					= 19;
 string	Mode2						= "0= Simple, 1= Exponential, 2= Smoothed, 3= Linear Weighted";
 int		MA_Mode2					= 2;
extern bool		Use_MA2_Slope				= false;
extern double	MA_Slope						= 1;
 string SMADist="----------------------";
 bool		Use_MA_Dist				= false;
 double	MA_Dist_Period			= 4;
 string	Mode0						= "0= Simple, 1= Exponential, 2= Smoothed, 3= Linear Weighted";
 double	MA_Dist_Mode			= 1;
 double	Dist_to_MA				= 4;
 string SBB="----------------------";
 bool		Use_BB					= false;
 int		BB_Period				= 10;
 int		BB_Dev					= 2;
 int		BB_Range					= 12;
 int		BB_Penetration			= 2;
 bool		Use_BB_Direction		= false;
 string SRSI="----------------------";
 bool		Use_RSI					= false;
 int		RSI_Period				= 70;
 double	RSI_Entry				= 50;

string S11="---------Global Variables---------------";

// globals
bool		Trade;
datetime	Last_Time;
double	Lot;
double	PointValue;
int		OrderSlippage;
double	LotStep,MinLot,MaxLot;
double	LastUpFractal,LastDownFractal;
double	midFractal;
//int		SpreadSampleSize = 10;  
#define SpreadSampleSize 10
double	Spread[SpreadSampleSize];
double	SortSpread[SpreadSampleSize];

bool		CCI_Buy_Sig;
bool		CCI_Sell_Sig;
bool		WPR_Buy_Sig;
bool		WPR_Sell_Sig;
bool		ATR_BuySell_Sig;
bool		MA_Buy_Sig1;
bool		MA_Sell_Sig1;
bool		MA_Buy_Sig2;
bool		MA_Sell_Sig2;
bool		Fractals_Buy_Sig;
bool		Fractals_Sell_Sig;  
bool		MA_Slope_Buy_Sig;               
bool		MA_Slope_Sell_Sig;
bool		BB_Buy_Sig;               
bool		BB_Sell_Sig;
bool		MA_Dist_Buy_Sig;               
bool		MA_Dist_Sell_Sig;
bool		RSI_Buy_Sig;               
bool		RSI_Sell_Sig;

bool		Trade_Pause_Buy_Sig = true;
bool		Trade_Pause_Sell_Sig = true;

bool		CCI_Exit_Buy_Sig;
bool		CCI_Exit_Sell_Sig;
bool		WPR_Exit_Buy_Sig;
bool		WPR_Exit_Sell_Sig; 

double	CCI_1,WPR_1,ATR_1,MA_1_1,MA_1_2,MA_2_1,MA_2_2,BB_U_1,BB_U_2,BB_U_3,BB_L_1,BB_L_2,BB_L_3,MA_3_1,RSI_1;

bool		SetDefaultsOK = false;
datetime	bt = 0;
int		ERR_GMT_Offset = 0;
bool		NewsTime;
int		minutesSincePrevEvent = 10080, minutesUntilNextEvent = 10080;
int		fhandle = -1;
string	fname;
double	Open_Hour,Close_Hour,Friday_Hour;
double	RO_Hour, RO_Start, RO_End;

int		MarketOrdersTotal;
int		LastOpenType;
double	LastBuyPrice;
double	LastSellPrice;
int		LastClosedType;
double	LastClosedPrice;
double	LastClosedProfit;
datetime	LastClosedTime;
double	LastAsk,LastBid;

int init()
{
	//----------------------------------- Check if min. 1 signal is activated ----------------------------//
	if(!Use_CCI && !Use_WPR && !Use_Fractals) {
   	Print("You must use at least one signal (CCI, WPR, or Fractals)");
		if(IsTesting()) {
			New_Trade = false; // switch off trading in BT if no signal is chosen
		} else {
   		Comment("You must use at least one signal (CCI, WPR, or Fractals)! Aborting...");
   		MessageBox("You must use at least one signal (CCI, WPR, or Fractals)! Aborting...", "Please use at least one signal", MB_OK|MB_ICONERROR);
   		while(true)
   			Sleep(1000);
		}
	}

	//----------------------- Check if either AutoConfig or proper GMT hours are used -----------------------//
	if(!AutoConfig && (GMT_Open_Hour<0.0 || GMT_Close_Hour<0.0 || GMT_Friday_Hour<0.0)) {
   	Print("You must use either AutoConfig or specify meaningful positive GMT trading hours (GMT_Open_Hour, GMT_Close_Hour, GMT_Friday_Hour)");
		if(IsTesting()) {
			New_Trade = false; // switch off trading in BT if no signal is chosen
		} else {
   		Comment("You must use either AutoConfig or specify meaningful positive GMT trading hours (GMT_Open_Hour, GMT_Close_Hour, GMT_Friday_Hour)! Aborting...");
   		MessageBox("You must use either AutoConfig or specify meaningful positive GMT trading hours (GMT_Open_Hour, GMT_Close_Hour, GMT_Friday_Hour)! Aborting...", "Please use AutoConfig or meaningful GMT hours", MB_OK|MB_ICONERROR);
   		while(true)
   			Sleep(1000);
		}
	}

	//----------------------------------- get GMT offset ----------------------------------------------------//
   if(AutoGMT)
   	if(IsTesting()) {
   		AutoGMT = false;
   		Print("WARNING: AutoGMT does not work in backtester! Using manual GMT_Offset = ", GMT_Offset);
   	} else if(!IsDllsAllowed()) {
   		Comment("Please enable DLLs for AutoGMT to work! Aborting...");
   		MessageBox("Please enable DLLs for AutoGMT to work! Aborting...", "Please enable DLLs", MB_OK|MB_ICONERROR);
   		while(true)
   			Sleep(1000);
   	} else
   		GMT_Offset = GetGMT_Offset();
	
	//--------------------------------- turn off news filter in BT---------------------------------------------//
	if(Use_NewsFilter && IsTesting()) {
		Use_NewsFilter = false;
   	Print("WARNING: NewsFilter does not work in backtester! Deactivated.");
	}
	
	//--------------------------------- initialize some globals -----------------------------------------------//
	PointValue = Point;
	if(Digits%2==1) {
		PointValue	*= 10.0;
		Slippage		*= 10.0;
	}
	OrderSlippage = MathRound(Slippage);

   LotStep = MarketInfo(Symbol(),MODE_LOTSTEP);
   MinLot = MarketInfo(Symbol(),MODE_MINLOT);
   MaxLot = MarketInfo(Symbol(),MODE_MAXLOT);
   
   LastAsk = Ask;
   LastBid = Bid;
	
	//--------------------------------- Set Magic Number ------------------------------------------------------//
	if(Magic <= 0 && StringLen(MagicKey) == 0 && !IsTesting())
		if(MessageBox("Please use parameter MagicKey to create unique Magic numbers which cannot be backtracked by your br0ker. Press OK to continue without MagicKey, or Cancel to cancel EA operation.","MagicKey",MB_OKCANCEL|MB_ICONQUESTION)==IDCANCEL)
			while(true)
				Sleep(1000);
  	
   if(Magic <= 0)
   	Magic = AutoMagic();
	
	//--------------------------------- Set Defaults ----------------------------------------------------------//
	if(AutoConfig)
		SetDefaultsOK = SetDefaults();

	//--------------------------------- adjust some globals to point value ------------------------------------//
	MidFractalDist			*= PointValue;
	OppositeFractalDist	*= PointValue;
	ATR_MinPips				*= PointValue;
	ATR_MaxPips				*= PointValue;
	Max_Spread				*= PointValue;
	
	//--------------------------------- Create global suspend variable ----------------------------------------//
	if(!GlobalVariableCheck("MNS_SUSPEND"))
		GlobalVariableSet("MNS_SUSPEND",0.0);

	//--------------------------------- Open slippage log -----------------------------------------------------//
	if(LogSlippage && LogToSeperateFile) {
		fname = StringConcatenate("SlipLog_",Symbol(),"_",Magic,".csv");
		
		if(IsTesting())
			fhandle = FileOpen(fname,FILE_CSV|FILE_WRITE);
		else
			fhandle = FileOpen(fname,FILE_CSV|FILE_READ|FILE_WRITE);
			
		if(fhandle!=-1) { // file opened
			if(FileSize(fhandle)==0) // empty file opened
				FileWrite(fhandle,"Date","Time","Ticket","Order Type","Sent","Executed","Slippage");
			else if(!IsTesting())
				FileSeek(fhandle,0,SEEK_END);
		}
		else { // could not open file
			LogToSeperateFile = false;
			Print("WARNING: Failed to open slippage log file. Logging to journal instead.");
		}
	}
	
	//--------------------------------- Set Trade Hours -------------------------------------------------------//
	SetTradeHrs();
	
	return (0);
} // end init()

int deinit()
{
	//Comment("");
	if(fhandle!=-1)
		FileClose(fhandle);
	
   return (0);
} // end deinit()

int start()
{
	static bool VariSpread = false, RolloverPeriod = false, DoFlush = false;
	int i;
	static int ticket = -1;
	double x, y, MedianSpread;
	
	if(AutoGMT) {
		// run every new bar openening
		if(bt != Time[0]) {
			// check every week if GMT and / or DST status has changed
			if(TimeDayOfWeek(bt) > 4 && DayOfWeek() < 2) {
				ERR_GMT_Offset = 0; // reset error counter
				GMT_Offset = GetGMT_Offset();
				SetTradeHrs();
			}
			bt = Time[0];
			if(!Hide_SL_TP && !IsRolloverPeriod())	// periodically check and correct SL and TP (may go out of whack during RO protection)
				ModifyAll(true);
		} else if(ERR_GMT_Offset>0) {		// in case GetGMT_Offset returned any errors
			GMT_Offset = GetGMT_Offset();	// try again to get GMT Offset
			if(ERR_GMT_Offset<10)			// retry count < 10? -> set hrs again
				SetTradeHrs();
			else									// if retry count reached -> give up
				ERR_GMT_Offset = 0;
		} // end if ERR_GMT_Offset>0
	} // end if AutoGMT
	
	//////////////////////////////////// Handle variable spreads ////////////////////////////////////
	if(VariSpread)
		MedianSpread = Spread(Ask-Bid);
	else if(Ask-Bid != LastAsk-LastBid) {
		Print("Variable spreads detected.");
		MedianSpread = Spread(Ask-Bid);
		VariSpread = true;
	} else
		MedianSpread = Spread();
	
	//////////////////////////// Trade Timing (and Rollover Protection) /////////////////////////////
	
	Trade = true;
	x = Hour() + Minute()/60.0; // server time in decimal hrs
	
	// Normal trading day rules
	if(Open_Hour < Close_Hour) {
		if(x<Open_Hour || x>=Close_Hour)
			Trade = false;
	} else if(x<Open_Hour && x>=Close_Hour)
		Trade = false;
	
	// NewsFilter
	if(Use_NewsFilter) {
		NewsTime = IsNewsTime();
		if(NewsTime)
			Trade = false;
	} else
		NewsTime = false;
	
	if(Trade) { // check other rules only if trade window open
		// Rollover time rules
		if(RolloverProtection) {
			if(!IsRolloverPeriod()) {
				// End of Rollover period
				if(RolloverPeriod) { // previous tick was rollover period
					RolloverPeriod = false;
					if(OrdersTotal()>0 && !Hide_SL_TP)
						ModifySL(StopLoss);
				}
			} else { // IsRolloverPeriod() == true
				// Start of Rollover Period
				Trade = false;
				if(!RolloverPeriod) { // previous tick was not rollover period
					RolloverPeriod = true;
					if(OrdersTotal()>0 && !Hide_SL_TP)
						ModifySL(StopLoss + SL_ExtraPips);
				}
			}
		}
		
		// Friday trading rules
		if(TimeDayOfWeek(TimeCurrent()-GMT_Offset*3600) == 5) // ERROR: does not consider DST
			if(!TradeOnFriday || x > Friday_Hour)
				Trade = false;
			
		// holiday season rules
		switch(Month()) {
			case 1:
				if(Day()<5)  // ERROR: goes by server time (not GMT time), does not consider DST
					Trade = false;
				break;
			case 12:
				if(Day()>22) // ERROR: goes by server time (not GMT time), does not consider DST
					Trade = false;
				break;
		}
		
		// global suspend
		if(GlobalVariableGet("MNS_SUSPEND")!=0.0)
			Trade = false;
	}
	
	/////////////////////////////  Indicator(s) /////////////////////////
	if(Trade || OrdersTotal()>0) { // used for entry or exit
		if(Use_CCI)
			CCI_1 = iCCI(NULL,0,CCI_Period,PRICE_CLOSE,0);
		if(Use_WPR)
			WPR_1 = iWPR(NULL,0,WPR_Period,0);
	}
	
	if(Trade) { // used for entry only
		if(Use_ATR)
			ATR_1 = iATR(NULL,0,ATR_Period,0);
		if(Use_MA1) {
			MA_1_1 = iMA(NULL,0,MA_Period1,0,MA_Mode1,PRICE_CLOSE,1);
			MA_1_2 = iMA(NULL,0,MA_Period1,0,MA_Mode1,PRICE_CLOSE,2);
		}
		if(Use_MA2 || Use_MA2_Slope) {
			MA_2_1 = iMA(NULL,0,MA_Period2,0,MA_Mode2,PRICE_CLOSE,1);
			MA_2_2 = iMA(NULL,0,MA_Period2,0,MA_Mode2,PRICE_CLOSE,2);
		}
		if(Use_MA_Dist)
			MA_3_1  = iMA(NULL,0,MA_Dist_Period,0,MA_Dist_Mode,PRICE_CLOSE,1);
		if(Use_BB) {
			BB_L_1  = iBands(NULL,0,BB_Period,BB_Dev,0,PRICE_CLOSE,MODE_LOWER,0);
			BB_L_2  = iBands(NULL,0,BB_Period,BB_Dev,0,PRICE_CLOSE,MODE_LOWER,1);
			BB_L_3  = iBands(NULL,0,BB_Period,BB_Dev,0,PRICE_CLOSE,MODE_LOWER,2);
			BB_U_1  = iBands(NULL,0,BB_Period,BB_Dev,0,PRICE_CLOSE,MODE_UPPER,0);
			BB_U_2  = iBands(NULL,0,BB_Period,BB_Dev,0,PRICE_CLOSE,MODE_UPPER,1);
			BB_U_3  = iBands(NULL,0,BB_Period,BB_Dev,0,PRICE_CLOSE,MODE_UPPER,2);
		}
		if(Use_RSI)
			RSI_1 = iRSI(NULL,0,RSI_Period,PRICE_CLOSE,0);
		if(Use_Fractals) {
			for(i=1;i<Bars;i++) {
				x=iFractals(NULL,0,MODE_UPPER,i);
				if(x!=0.0) {
					LastUpFractal=x;
					break;
				}
			}
			for(i=1;i<Bars;i++) {
				x=iFractals(NULL,0,MODE_LOWER,i);
				if(x!=0.0) {
					LastDownFractal=x;
					break;
				}
			}
			midFractal=(LastUpFractal+LastDownFractal)/2.0; 
		} // end UseFractals
	}   
	
	//////////////////////////////////// Enter Trade Signals /////////////////////////////////////////      
	if(Trade) {
		CCI_Buy_Sig				= true;
		CCI_Sell_Sig			= true;
		WPR_Buy_Sig				= true;
		WPR_Sell_Sig			= true;
		ATR_BuySell_Sig		= true;
		MA_Buy_Sig1				= true;
		MA_Sell_Sig1			= true;
		MA_Buy_Sig2				= true;
		MA_Sell_Sig2			= true;
		MA_Slope_Buy_Sig		= true;
		MA_Slope_Sell_Sig		= true;
		MA_Dist_Buy_Sig		= true;
		MA_Dist_Sell_Sig		= true;
		Fractals_Buy_Sig		= true;
		Fractals_Sell_Sig		= true;
		BB_Buy_Sig				= true;
		BB_Sell_Sig				= true;
		RSI_Buy_Sig				= true;
		RSI_Sell_Sig			= true;
		
		if(Use_CCI) {
			if(!(CCI_1<-CCI_Entry)) CCI_Buy_Sig=false;
			if(!(CCI_1>CCI_Entry)) CCI_Sell_Sig=false;
		}
		
		if(Use_WPR) {
			if(!(WPR_1<-WPR_Entry)) WPR_Buy_Sig=false;
			if(!(WPR_1>-100+WPR_Entry)) WPR_Sell_Sig=false;
		}
		
		if(Use_ATR)
			if(ATR_1<ATR_MinPips || ATR_1>ATR_MaxPips) ATR_BuySell_Sig=false;
		
		if(Use_MA1) {
			if(!(MA_1_1>MA_1_2)) MA_Buy_Sig1=false;
			if(!(MA_1_1<MA_1_2)) MA_Sell_Sig1=false;
		}
		
		if(Use_MA2) {
			if(!(MA_2_1>MA_2_2)) MA_Buy_Sig2=false;
			if(!(MA_2_1<MA_2_2)) MA_Sell_Sig2=false;
		}
		
		if(Use_MA2_Slope) {
			if(!(MA_2_1-MA_2_2>=MA_Slope*PointValue)) MA_Slope_Buy_Sig=false;
			if(!(MA_2_2-MA_2_1>=MA_Slope*PointValue)) MA_Slope_Sell_Sig=false;
		}
		
		if(Use_MA_Dist) {
			x = Dist_to_MA*PointValue;
			if(MA_3_1-Ask>=x) MA_Dist_Buy_Sig=false;
			if(Bid-MA_3_1>=x) MA_Dist_Sell_Sig=false;
		}
		
		if(Use_Fractals) {
			if(!(Ask<midFractal-MidFractalDist && Ask<LastUpFractal-OppositeFractalDist)) Fractals_Buy_Sig=false;
			if(!(Bid>midFractal+MidFractalDist && Bid>LastDownFractal+OppositeFractalDist)) Fractals_Sell_Sig=false;
		}
		
		if(Use_BB) {
			x = BB_Range*PointValue;
			y = BB_Penetration*PointValue;
			if(!(!Use_BB_Direction && Ask<BB_L_1 && (BB_U_1-BB_L_1)>x && BB_L_1-Ask>=y)) BB_Buy_Sig=false;
			if(!(!Use_BB_Direction && Bid>BB_U_1 && (BB_U_1-BB_L_1)>x && Bid-BB_U_1>=y)) BB_Sell_Sig=false;
			if(!(Use_BB_Direction && Ask<BB_L_1 && (BB_U_1-BB_L_1)>x && BB_L_1-Ask>=y && BB_L_1>BB_L_2)) BB_Buy_Sig=false;
			if(!(Use_BB_Direction && Bid>BB_U_1 && (BB_U_1-BB_L_1)>x && Bid-BB_U_1>=y && BB_U_1<BB_U_2)) BB_Sell_Sig=false;
		}
		
		if(Use_RSI) {
			if(!(RSI_1>=RSI_Entry)) RSI_Buy_Sig=false;
			if(!(RSI_1<=100-RSI_Entry)) RSI_Sell_Sig=false;
		}
	}
	
	if(Trade_Pause_On_Loss) {
		Trade_Pause_Buy_Sig	= true;
		Trade_Pause_Sell_Sig	= true;
		
		GetLastClosed();
		
		switch(Pause_Type) {
			case 1:
				if(LastClosedProfit<0 && (Time[0]-LastClosedTime)<Trade_Pause_Minutes*60)
					if(LastClosedType==0)
						Trade_Pause_Buy_Sig=false;
					else if(LastClosedType==1)
						Trade_Pause_Sell_Sig=false;
				break;
			case 2:
				if(LastClosedType==0 && LastClosedPrice-Ask<Trade_Pause_Pips*PointValue)
					Trade_Pause_Buy_Sig=false;
				else if(LastClosedType==1 && Bid-LastClosedPrice<Trade_Pause_Pips*PointValue)
					Trade_Pause_Sell_Sig=false;
				break;
		}
	}
	
	//////////////////////////////////// Exit Trade Signals /////////////////////////////////////////      
	if(OrdersTotal()>0) {
		CCI_Exit_Buy_Sig	= false;
		CCI_Exit_Sell_Sig	= false;
		WPR_Exit_Buy_Sig	= false;
		WPR_Exit_Sell_Sig	= false;
		
		if(Use_CCI) {
			if(CCI_1>CCI_Exit) CCI_Exit_Buy_Sig=true;
			if(CCI_1<-CCI_Exit) CCI_Exit_Sell_Sig=true;
		}
		if(Use_WPR) {
			if(WPR_1>-WPR_Exit) WPR_Exit_Buy_Sig=true;
			if(WPR_1<-100+WPR_Exit) WPR_Exit_Sell_Sig=true;
		}
	}
	
	//////////////////////////////////// Close Trades ///////////////////////////////////////////////      
	if(OrdersTotal()>0) {
		// close by signal
		if(CCI_Exit_Buy_Sig || WPR_Exit_Buy_Sig || CCI_Exit_Sell_Sig || WPR_Exit_Sell_Sig) { // any signal true?
			if(IsCloseSpreadOK(MedianSpread))
				for(i=0;i<OrdersTotal();i++) {
					if(OrderSelect(i,SELECT_BY_POS, MODE_TRADES))
						if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
							switch(OrderType()) {
								case OP_BUY:
									if(CCI_Exit_Buy_Sig || WPR_Exit_Buy_Sig)
										DoFlush = CloseAll();
									break;
								case OP_SELL:
									if(CCI_Exit_Sell_Sig || WPR_Exit_Sell_Sig)
										DoFlush = CloseAll();
									break;
							} // end switch
				} // end for
		} // end if any signal
		// check and close by "hidden" SL and TP
		if(Hide_SL_TP) {
			if(RolloverProtection && IsRolloverPeriod())
				x = (StopLoss + SL_ExtraPips)*PointValue;
			else
				x = StopLoss*PointValue;
    		for(i=0; i<OrdersTotal(); i++) {
    			OrderSelect(i,SELECT_BY_POS, MODE_TRADES);
    			if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
    				switch(OrderType()) {
						case OP_BUY:
							if(Ask-OrderOpenPrice()>=TakeProfit*PointValue || OrderOpenPrice()-Ask>=x)
								if(OrderClose(OrderTicket(),OrderLots(),Bid,OrderSlippage,Navy)) // close position
									if(LogSlippage)
										DoFlush = LogSlip(fhandle,OrderTicket(),Bid,OrderClosePrice(),(OrderClosePrice()-Bid)/PointValue);
							break;
						case OP_SELL:
							if(OrderOpenPrice()-Bid>=TakeProfit*PointValue || Bid-OrderOpenPrice()>=x)
								if(OrderClose(OrderTicket(),OrderLots(),Ask,OrderSlippage,Maroon)) // close position
									if(LogSlippage)
										DoFlush = LogSlip(fhandle,OrderTicket(),Ask,OrderClosePrice(),(Ask-OrderClosePrice())/PointValue);
							break;
    				}
			} // end for
		} // end if(Hide_SL_TP)
	} // end if(OrdersTotal()>0)
	
	//////////////////////////////////// Open Trade ///////////////////////////////////////////////
	if(Trade) { // only check if it is trade open time
		MarketOrdersTotal = CountMarketOrders();
		if(New_Trade && Time[0]!=Last_Time && MarketOrdersTotal==0) // common prerequisite for all new OrderSelect
			if(CCI_Buy_Sig && WPR_Buy_Sig && ATR_BuySell_Sig && MA_Buy_Sig1 && MA_Buy_Sig2 && MA_Slope_Buy_Sig && MA_Dist_Buy_Sig && Fractals_Buy_Sig && BB_Buy_Sig && RSI_Buy_Sig && Trade_Pause_Buy_Sig) { // check all BUY signals
				if(Ask-Bid<=MedianSpread && Ask-Bid<=Max_Spread) { // check spreads
					Lot = CalculateLots(Risk);
					ticket = OrderSend(Symbol(), OP_BUY, Lot, Ask, OrderSlippage, 0, 0, EA_Comment, Magic, 0, DeepSkyBlue);
					if(ticket>0) {
						Last_Time=iTime(NULL,0,0);
						if(LogSlippage)
							DoFlush = LogSlip(fhandle,ticket,Ask,OrderOpenPrice(),(Ask-OrderOpenPrice())/PointValue);
						if(!Hide_SL_TP)
							ModifyAll();
					}
				} // end check spreads
			} // end check all BUY signals
			else if(CCI_Sell_Sig && WPR_Sell_Sig && ATR_BuySell_Sig && MA_Sell_Sig1 && MA_Sell_Sig2 && MA_Slope_Sell_Sig && MA_Dist_Sell_Sig && Fractals_Sell_Sig && BB_Sell_Sig && RSI_Sell_Sig && Trade_Pause_Sell_Sig) { // check all SELL signals
				if(Ask-Bid<=MedianSpread && Ask-Bid<=Max_Spread) { // check spreads
					Lot=CalculateLots(Risk);
					ticket = OrderSend(Symbol(), OP_SELL, Lot, Bid, OrderSlippage, 0, 0, EA_Comment, Magic, 0, HotPink);
      			if(ticket>0) {
      				Last_Time=iTime(NULL,0,0);
						if(LogSlippage)
							DoFlush = LogSlip(fhandle,ticket,Bid,OrderOpenPrice(),(OrderOpenPrice()-Bid)/PointValue);
      				if(!Hide_SL_TP)
      					ModifyAll();
      			}
				} // end check spreads
			} // end check all SELL signals
	} // end if Trade
	
	//////////////////////////////////// Second Trade ///////////////////////////////////////////////   
	if(Trade && Allow_Second_Open_Trade) {
		GetLastOpen();
		if(MarketOrdersTotal==1 && Time[0]!=Last_Time && Trade_Pause_Buy_Sig && LastOpenType==OP_BUY && Ask<=(LastBuyPrice-Distance*PointValue)) {
			Lot=CalculateLots(Risk*Lot_Factor);
			ticket = OrderSend(Symbol(), OP_BUY, Lot, Ask, OrderSlippage, 0, 0, EA_Comment, Magic, 0, MediumBlue);
			if(ticket>0) {
				Last_Time=iTime(NULL,0,0);
				if(LogSlippage)
					DoFlush = LogSlip(fhandle,ticket,Ask,OrderOpenPrice(),(Ask-OrderOpenPrice())/PointValue);
				if(!Hide_SL_TP)
					ModifyAll();
			}
		} else if(MarketOrdersTotal==1 && Time[0]!=Last_Time && Trade_Pause_Sell_Sig && LastOpenType==OP_SELL && Bid>=(LastSellPrice+Distance*PointValue)) {
			Lot=CalculateLots(Risk*Lot_Factor);
			ticket = OrderSend(Symbol(), OP_SELL, Lot, Bid, OrderSlippage, 0, 0, EA_Comment, Magic, 0, Red);
			if(ticket>0) {
				Last_Time=iTime(NULL,0,0);
				if(LogSlippage)
					DoFlush = LogSlip(fhandle,ticket,Bid,OrderOpenPrice(),(OrderOpenPrice()-Bid)/PointValue);
				if(!Hide_SL_TP)
					ModifyAll();
			}
		}
	} // end Allow_Second_Open_Trade
	
	// do some stuff only needed in live trading (not in BT)
	if (!IsTesting()) {
		// Double check to make sure all trades have TP and SL
		if(!Hide_SL_TP)
			ModifyAll();
		if(DoFlush) {
			FileFlush(fhandle);
			DoFlush = false;
		}
	}
	
	////////////////////////////  Add Display (HUD & fractal levels indi) /////////////////////////////
	if(!IsTesting() || IsVisualMode()) {
		HUD(MedianSpread);
		if(Show_Fractal_Levels)
			iCustom(NULL,0,"Fractal_Levels",MidFractalDist/PointValue,OppositeFractalDist/PointValue,0,0);
	}
	
	////////////////////////////  save Bid & Ask for next tick ////////////////////////////////////////
	if(!VariSpread) {
		LastAsk = Ask;
		LastBid = Bid;
	}
	
	return (0);
} // end start()

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

int CountMarketOrders()
{
	int i, n=0;
	
	for(i=0;i<OrdersTotal();i++) {
		OrderSelect(i,SELECT_BY_POS);
		if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic && OrderType()<=OP_SELL)
			n++;
	}
	
	return(n);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

void GetLastOpen()
{
	int i;
	
	LastOpenType = -1;
	LastBuyPrice = 0.0;
	LastSellPrice = 0.0;
	
	for(i=0;i<OrdersTotal();i++) {
		OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
		if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic) {
			switch(OrderType()) {
				case OP_BUY:
					LastOpenType = OP_BUY;
					LastBuyPrice = OrderOpenPrice();
					break;
				case OP_SELL:
					LastOpenType = OP_SELL;
					LastSellPrice = OrderOpenPrice();
					break;
			} // end switch
		} // end if
	} // end for
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

void GetLastClosed()
{
	int i, low = 0;
	int cticket = -1;
	datetime ctime = 0;
	
   if(IsTesting())
   	low=OrdersHistoryTotal()-2;
	
	LastClosedType = -1;
	LastClosedPrice = 0.0;
	LastClosedProfit = 0.0;
	LastClosedTime = 0;
	
	for(i=OrdersHistoryTotal()-1;i>=low;i--) {
		OrderSelect(i,SELECT_BY_POS,MODE_HISTORY);
		if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic && OrderType()<=OP_SELL) {
			ctime = OrderCloseTime();
			if(ctime>LastClosedTime || (ctime==LastClosedTime && OrderTicket() > cticket)) {
				cticket = OrderTicket();
				LastClosedType = OrderType();
				LastClosedPrice = OrderClosePrice();
				LastClosedProfit = OrderProfit()+OrderCommission();
				LastClosedTime = ctime;
			} // end if
		} // end if
	} // end for
}

////////////////////////////////////////////////////////////////////////////////////////////////////////

// returns true if order(s) closed and written to external slippage log -> requiring FileFlush
bool CloseAll() 
{
	bool rval = false;
	int i;
	
	for (i=OrdersTotal()-1;i>=0;i--) {
		OrderSelect(i,SELECT_BY_POS);
		if (OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
			switch(OrderType()) {
				case OP_BUY:
					if(OrderClose(OrderTicket(),OrderLots(),Bid,OrderSlippage,Navy))
						if(LogSlippage)
							if(LogSlip(fhandle,OrderTicket(),Bid,OrderClosePrice(),(OrderClosePrice()-Bid)/PointValue))
								rval = true;
					break;
				case OP_SELL:
					if(OrderClose(OrderTicket(),OrderLots(),Ask,OrderSlippage,Maroon))
						if(LogSlippage)
							if(LogSlip(fhandle,OrderTicket(),Ask,OrderClosePrice(),(Ask-OrderClosePrice())/PointValue))
								rval = true;
					break;
			}
	}
	
	return(rval);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

double CalculateLots(double r) 
{
   int SL = 1000;
   double rval;
   
   if(LotSize>0.0)
   	rval = LotSize;
   else
   	rval = AccountBalance()*(r/100.0)/(SL*MarketInfo(Symbol(),MODE_TICKVALUE)*Point/MarketInfo(Symbol(),MODE_TICKSIZE));
   
   return(MathMin(MathMax(MinLot,MathRound(rval/LotStep)*LotStep),MaxLot));
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ModifyAll(bool force = false) 
{
	for(int i=OrdersTotal()-1; i>=0; i--) {
		OrderSelect(i,SELECT_BY_POS);
		if (OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
			if(force || OrderStopLoss()==0.0 || OrderTakeProfit()==0.0)
				switch(OrderType()) {
					case OP_BUY:
						OrderModify(OrderTicket(),OrderOpenPrice(),ND(OrderOpenPrice()-StopLoss*PointValue),ND(OrderOpenPrice()+TakeProfit*PointValue),0,Green);
						break;
					case OP_SELL:
						OrderModify(OrderTicket(),OrderOpenPrice(),ND(OrderOpenPrice()+StopLoss*PointValue),ND(OrderOpenPrice()-TakeProfit*PointValue),0,Red);
						break;
				}
	} // end for
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ModifySL(double sl = 0.0) 
{
	if(sl != 0.0)
		for(int i=OrdersTotal()-1; i>=0; i--) {
			OrderSelect(i,SELECT_BY_POS);
			if (OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
				switch(OrderType()) {
					case OP_BUY:
						OrderModify(OrderTicket(),OrderOpenPrice(),ND(OrderOpenPrice()-sl*PointValue),OrderTakeProfit(),0,Green);
						break;
					case OP_SELL:
						OrderModify(OrderTicket(),OrderOpenPrice(),ND(OrderOpenPrice()+sl*PointValue),OrderTakeProfit(),0,Red);
						break;
				}
		} // end for
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// return median spread
double Spread(double x=-1.0)
{
	static int iS = -1, mpos;
	
	// first call - initialize both spread arrays and median position index
	if(iS==-1)
		if(ArrayInitialize(Spread,Ask-Bid)==SpreadSampleSize) 
			if(ArrayCopy(SortSpread,Spread)==SpreadSampleSize) {
				mpos = SpreadSampleSize/2-1;
				iS = 0;
			}
	
	// if called with actual spread, update sample array
	if(x!=-1.0) {
		if(iS==SpreadSampleSize)
			iS = 0;
		Spread[iS] = x;
		iS++;
		ArrayCopy(SortSpread,Spread);
		ArraySort(SortSpread);
	}
	
	// return median spread (= actual spread in case of first call or fixed spreads)
	return(SortSpread[mpos]);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool IsCloseSpreadOK(double MedianSpread)
{
	if(!CloseByActualSpread && !CloseByMedianSpread) // if both switches are false then always OK
		return(true);
	else if(CloseByActualSpread && !CloseByMedianSpread && Ask-Bid<=Max_Spread) // consider only actual <= max spread
		return(true);
	else if(!CloseByActualSpread && CloseByMedianSpread && Ask-Bid<=MedianSpread) // consider only actual <= median spread
		return(true);
	else if(Ask-Bid<=Max_Spread && Ask-Bid<=MedianSpread) // both switches true, consider both spread criteria
		return(true);
	else
		return(false);
}			


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

double ND(double Price=0.0)
{
	return(NormalizeDouble(Price,Digits));
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

double HistoryProfit()
{
	double profit = 0.0;
	
	for(int i=0;i<OrdersHistoryTotal();i++) {
		if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY))
			continue;
		if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
			profit+=OrderProfit();
	}
	
	return (profit);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

double MarketProfit()
{
	double profit=0.0;
	
	for(int i=0;i<OrdersTotal();i++) {
		if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
			continue;
		if(OrderSymbol()== Symbol()&& OrderMagicNumber()==Magic && OrderType()<=OP_SELL)
			profit+=OrderProfit();
	}
	
	return(profit);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// automagic number generator
int AutoMagic()
{
   int m, dE;
   string s;
   
	s = StringConcatenate(EA_Name,MagicKey,Symbol(),Period(),DoubleToStr(AccountNumber(),0),AccountCompany());
      
   m = djb2(s);
   if(m < 0)
   	m = -m;
   dE = MathPow(10.0,MathMod(m/7,4)+5);
  	m = MathMod(m,dE)+(m-MathMod(m,dE))/dE;
  	if(m > dE)
  		m = MathMod(m,dE);
  	
  	return(m);
}

// djb2 hash
int djb2(string key){
	int i, h = 5381, c;
	for (i = 0; i < StringLen(key); i++){
		c = StringGetChar(key, i);
		h = (h << 5) + h + c;
	}
	return(h);
}

//------ Get GMT Offset by GetTimeZoneInformation() - modified from CrapperQuotes source ------//
int GMT_Off_GetTimeZoneInformation()
{
	int a[43],offlocmin,n;
	
	n=TimeCurrent()-TimeLocal(); // server time - local time, in seconds
	
	switch (GetTimeZoneInformation(a)) {
		case 0: // no daylight saving in local time zone, or unkown
			offlocmin=a[0];
			break;
		case 1: // local system is operating in standard time (no daylight saving time)
			offlocmin=a[0];
			break;
		case 2: // local system is operating in daylight saving time
			offlocmin=a[0]+a[42];
			break;
	}
	
	return(MathRound(n/3600.0-offlocmin/60.0));
}

//------ Get GMT Offset by GetSystemTime() - unknown source ------//
int GMT_Off_GetSystemTime()
{
	double GMT_Diff;
	int SYSTEMTIME[4];
	int nYear, nMonth, nDay, nHour, nMin, nSec, nMilliSec;
	string sMonth, sDay, sHour, sMin, sSec;
	string sUTC_Time;
	
	GetSystemTime(SYSTEMTIME);
	nYear     = SYSTEMTIME[0]&0x0000FFFF;
	nMonth    = SYSTEMTIME[0]>>16;
	nDay      = SYSTEMTIME[1]>>16;
	nHour     = SYSTEMTIME[2]&0x0000FFFF;
	nMin      = SYSTEMTIME[2]>>16;
	nSec      = SYSTEMTIME[3]&0x0000FFFF;
	nMilliSec = SYSTEMTIME[3]>>16;
	
	sMonth = 100 + nMonth;
	sMonth = StringSubstr(sMonth, 1);
	sDay   = 100 + nDay;
	sDay   = StringSubstr(sDay, 1);
	sHour  = 100 + nHour;
	sHour  = StringSubstr(sHour, 1);
	sMin   = 100 + nMin;
	sMin   = StringSubstr(sMin, 1);
	sSec   = 100 + nSec;
	sSec   = StringSubstr(sSec, 1);
	
	sUTC_Time = StringConcatenate(nYear,".",sMonth,".",sDay," ",sHour,":",sMin,":",sSec);
	
	GMT_Diff = TimeCurrent() - StrToTime(sUTC_Time);
	
	return(MathRound(GMT_Diff / 3600.0));
}

// Get GMT Offset in several possible ways
int GetGMT_Offset()
{
	bool IsPlausible1=false,IsPlausible2=false,IsIdentical=false; 
	int GMT_Offset1, GMT_Offset2;
	
	GMT_Offset1 = GMT_Off_GetSystemTime();
	GMT_Offset2 = GMT_Off_GetTimeZoneInformation();
	
	if(-12<=GMT_Offset1 && GMT_Offset1<=12)
		IsPlausible1=true;
	if(-12<=GMT_Offset2 && GMT_Offset2<=12)
		IsPlausible2=true;
	if(GMT_Offset1==GMT_Offset2)
		IsIdentical=true;
	
	if(IsIdentical && IsPlausible1) {
		ERR_GMT_Offset = 0;
		return(GMT_Offset1);
	}
	
	ERR_GMT_Offset++; // if not identical or not plausible, then increase error counter and return most suitable value
	
	if(IsPlausible1 && !IsPlausible2)
		return(GMT_Offset1);
	else if(!IsPlausible1 && IsPlausible2)
		return(GMT_Offset2);
	else // leave unchanged
		return(GMT_Offset);
}

// return true if current server time is in DST days for EST/EDT - alterntive implementation
bool IsEDT()
{
	if(Month()>3 && Month()<11) // Apr - Oct -> EDT
		return(true);
	
	if(Month()<3 || Month()>11) // Dec - Feb -> no EDT
		return(false);
	
	if(Month()==3) // March
		if(Day()>7+DayOfWeek())
			return(true);
		else
			return(false);
	
	if(Month()==11) // November
		if(Day()>DayOfWeek())
			return(false);
		else
			return(true);
}

// Set Trading Hours after GMT_Offset change
void SetTradeHrs()
{
	double DST_Offset = 0.0;
	
	if(IsEDT())
		DST_Offset = 1.0;
	if(IsTesting() && !AdjustForDST)
			DST_Offset = 0.0;
	
	Open_Hour	= GMT_Open_Hour   + GMT_Offset - DST_Offset;
	Close_Hour	= GMT_Close_Hour  + GMT_Offset - DST_Offset;
	Friday_Hour	= GMT_Friday_Hour + GMT_Offset - DST_Offset;
	
	RO_Hour		= 22.0				+ GMT_Offset - DST_Offset;
	RO_Start		= RO_Hour 			- MinsBeforeRollover/60.0;
	RO_End		= RO_Hour			+ MinsAfterRollover/60.0;
	
	if(Open_Hour>=24.0)
		Open_Hour-=24.0;
	if(Close_Hour>=24.0)
		Close_Hour-=24.0;
	if(Friday_Hour>=24.0)
		Friday_Hour-=24.0;
	if(RO_Hour>=24.0)
		RO_Hour-=24.0;
	if(RO_Start>=24.0)
		RO_Start-=24.0;
	if(RO_End>=24.0)
		RO_End-=24.0;
	
	//Print("RO_Start : ",RO_Start," RO_End : ",RO_End);
}

bool IsNewsTime()
{
	static bool rval = false;
	static int lm = -1;
	// uncomment next line if not global variable
	//int minutesSincePrevEvent, minutesUntilNextEvent;
	
	if (lm != Minute()) { // 
		lm = Minute();
		minutesSincePrevEvent = iCustom(NULL,0,"FFCal",IncludeHigh,IncludeMedium,IncludeLow,IncludeSpeaks,true,1,0);
		minutesUntilNextEvent = iCustom(NULL,0,"FFCal",IncludeHigh,IncludeMedium,IncludeLow,IncludeSpeaks,true,1,1);
		
		if(minutesUntilNextEvent<=MinsBeforeNews || minutesSincePrevEvent<=MinsAfterNews)
			rval = true;
		else
			rval = false;
	}
	
	return(rval);
}

bool IsRolloverPeriod()
{
	bool rval = true;
	double t;
	
	t = Hour() + Minute()/60.0; // server time in decimal hrs
	
	if(RO_Start<RO_End) {
		if(t<RO_Start || t>=RO_End)
			rval = false;
	} else if(t<RO_Start && t>=RO_End)
			rval = false;
	
	return(rval);
}

string DoubleToHHMM(double hrs)
{
	string HH, MM, HHMM;
	
	hrs = MathMod(hrs, 24.0);
	HH = StringSubstr(DoubleToStr(100.0 + MathFloor(hrs), 0), 1);
	hrs -= MathFloor(hrs);
	hrs *= 0.6;
	MM = StringSubstr(DoubleToStr(100.0 * hrs + 100.0,0), 1);
	HHMM = StringConcatenate(HH, ":", MM);
	
	return(HHMM);
}

// returns true if written to external log and requiring FileFlush
bool LogSlip(int fhandle, int ticket, double prc1, double prc2, double prc3)
{
	bool rval = false;
	
	if(OrderSelect(ticket, SELECT_BY_TICKET))
		switch(OrderCloseTime()) {
			case 0: // open (or pending) order
				if(OrderType()==OP_BUY) { // open buy order
					if(LogToSeperateFile && fhandle!=-1) {
						if(FileWrite(fhandle,TimeToStr(TimeCurrent(),TIME_DATE),TimeToStr(TimeCurrent(),TIME_SECONDS),ticket,"open BUY",Ask,OrderOpenPrice(),(Ask-OrderOpenPrice())/PointValue)>0)
							rval = true;
					} else
						Print("order #",ticket," open buy sent: ",DoubleToStr(Ask,Digits)," executed: ",DoubleToStr(OrderOpenPrice(),Digits)," slippage: ",(Ask-OrderOpenPrice())/PointValue);
				} else if(OrderType()==OP_SELL) { // open sell order
					if(LogToSeperateFile && fhandle!=-1) {
						if(FileWrite(fhandle,TimeToStr(TimeCurrent(),TIME_DATE),TimeToStr(TimeCurrent(),TIME_SECONDS),ticket,"open SELL",Bid,OrderOpenPrice(),(OrderOpenPrice()-Bid)/PointValue)>0)
							rval = true;
					} else
						Print("order #",ticket," open sell sent: ",DoubleToStr(Bid,Digits)," executed: ",DoubleToStr(OrderOpenPrice(),Digits)," slippage: ",(OrderOpenPrice()-Bid)/PointValue);
				}
				break;
			default: // closed order
				if(OrderType()==OP_BUY) { // closed buy order
					if(LogToSeperateFile && fhandle!=-1) {
						if(FileWrite(fhandle,TimeToStr(TimeCurrent(),TIME_DATE),TimeToStr(TimeCurrent(),TIME_SECONDS),OrderTicket(),"close BUY",Bid,OrderClosePrice(),(OrderClosePrice()-Bid)/PointValue)>0)
							rval = true;
					} else
						Print("order #",OrderTicket()," close buy sent: ",DoubleToStr(Bid,Digits)," executed: ",DoubleToStr(OrderClosePrice(),Digits)," slippage: ",(OrderClosePrice()-Bid)/PointValue);
				} else if(OrderType()==OP_SELL) { // closed sell order
					if(LogToSeperateFile && fhandle!=-1) {
						if(FileWrite(fhandle,TimeToStr(TimeCurrent(),TIME_DATE),TimeToStr(TimeCurrent(),TIME_SECONDS),OrderTicket(),"close SELL",Ask,OrderClosePrice(),(Ask-OrderClosePrice())/PointValue)>0)
							rval = true;
					} else
						Print("order #",OrderTicket()," close sell sent: ",DoubleToStr(Ask,Digits)," executed: ",DoubleToStr(OrderClosePrice(),Digits)," slippage: ",(Ask-OrderClosePrice())/PointValue);
				}
				break;
		}
	
	return(rval);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void HUD(double MedianSpread)
{
	string Session, InstrumentStatus, RiskMode;
	
	MarketOrdersTotal = CountMarketOrders();
	
	// Trade session open, no trades entered
	if(Trade && MarketOrdersTotal==0) {
		Session="Trade Session Open";
		if(Ask-Bid<=MedianSpread && Ask-Bid<=Max_Spread)
			Session=StringConcatenate(Session," .. Waiting for trades");
		else
			Session=StringConcatenate(Session," .. Spread is High .. Trading Halted");
	}
	
	// Trade session open, 1+ trade entered
	if(Trade && MarketOrdersTotal>0) {
		Session="Trade Session Open .. Waiting to exit trades";
		if(!IsCloseSpreadOK(MedianSpread))
			Session=StringConcatenate(Session," .. Spread is High");
	}
	
	// Trade session over
	if(!Trade) {
		if(GlobalVariableGet("MNS_SUSPEND")!=0.0)
			Session="Trading suspended by GVAR";
		else if(RolloverProtection && IsRolloverPeriod())
			Session="Rollover Protection Active";
		else if(NewsTime)
			Session="News Time";
		else
			Session="Trade Session Closed";
		if(MarketOrdersTotal>0)	{
			Session=StringConcatenate(Session," .. Waiting to exit trades");
			if(!IsCloseSpreadOK(MedianSpread))
				Session=StringConcatenate(Session," .. Spread is High");
		}
	}
	
	InstrumentStatus = StringConcatenate("\n    ",Symbol());
	if(SetDefaultsOK)
		InstrumentStatus = StringConcatenate(InstrumentStatus, " (auto configured)");
	else
		InstrumentStatus = StringConcatenate(InstrumentStatus, " (manual settings)");
	
	if(LotSize>0.0)
		RiskMode = "\n    Using Manual Fixed Lots";
	else
		RiskMode = StringConcatenate("\n    Risk                     = ",DoubleToStr(Risk,1));
	
   Comment(	"*=====================*",
				"\n    "+EA_Name,
				"\n    v"+EA_Version+" modded by pip.digger",
				"\n*=====================*",
				InstrumentStatus,
				"\n    Magic Number       = "+Magic,
				"\n*=====================*",
				"\n    "+Session,
				"\n*=====================*",
				"\n    Broker Time          = ",TimeToStr(TimeCurrent(), TIME_MINUTES|TIME_SECONDS),
				"\n    GMT Time            = ",TimeToStr(TimeCurrent()-GMT_Offset*3600,TIME_MINUTES|TIME_SECONDS),
				"\n    GMT Offset          = ",GMT_Offset,
				"\n    Start  Broker/GMT = ",DoubleToHHMM(Open_Hour)," / ",DoubleToHHMM(GMT_Open_Hour),
				"\n    End   Broker/GMT = ",DoubleToHHMM(Close_Hour)," / ",DoubleToHHMM(GMT_Close_Hour),
				"\n",
				"\n    Spreads:",
				"\n    actual/median/max = ",DoubleToStr((Ask-Bid)/PointValue,1)," / ",DoubleToStr(MedianSpread/PointValue,1)," / ",DoubleToStr(Max_Spread/PointValue,1),
				"\n*=====================*",
				RiskMode,
				"\n    Lot Size                = ",DoubleToStr(CalculateLots(Risk),2),
				"\n    Leverage              = 1:",AccountLeverage(),
				"\n*=====================*",
				"\n    Total Profit (Loss)   = ",DoubleToStr(HistoryProfit()+MarketProfit(),2),
				"\n*=====================*"
				);
} 

bool SetDefaults()
{
	if(StringFind(Symbol(),"EURCAD")!=-1) {
		if(Max_Spread==0)Max_Spread=6;if(Risk==0.0)Risk=7.5;TakeProfit=60.0;StopLoss=60.0;
		if(GMT_Open_Hour<0.0)GMT_Open_Hour=21.0;if(GMT_Close_Hour<0.0)GMT_Close_Hour=24.0;if(GMT_Friday_Hour<0.0)GMT_Friday_Hour=16.0;
		Allow_Second_Open_Trade=false;
		Use_CCI			= true;CCI_Period=10;CCI_Entry=100;CCI_Exit=120;
		Use_WPR			= true;WPR_Period=10;WPR_Entry=91;WPR_Exit=40;
		Use_Fractals	= true;MidFractalDist=6;OppositeFractalDist=11;
		Use_ATR			= false;
		Use_MA1			= false;
		Use_MA2			= false;
		Use_MA2_Slope	= false;
		Use_MA_Dist		= false;
		Use_BB			= false;
		Use_RSI			= false;
	} else if(StringFind(Symbol(),"EURGBP")!=-1) {
 		if(Max_Spread==0)Max_Spread=4;if(Risk==0.0)Risk=7.5;TakeProfit=60.0;StopLoss=60.0;
		if(GMT_Open_Hour<0.0)GMT_Open_Hour=21.0;if(GMT_Close_Hour<0.0)GMT_Close_Hour=24.0;if(GMT_Friday_Hour<0.0)GMT_Friday_Hour=16.0;
		Allow_Second_Open_Trade=false;
 		Use_CCI			= true;CCI_Period=10;CCI_Entry=100;CCI_Exit=120;
 		Use_WPR			= true;WPR_Period=11;WPR_Entry=90;WPR_Exit=40;
 		Use_Fractals	= true;MidFractalDist=5;OppositeFractalDist=9;
		Use_ATR			= false;
		Use_MA1			= false;
		Use_MA2			= false;
		Use_MA2_Slope	= false;
		Use_MA_Dist		= false;
		Use_BB			= false;
		Use_RSI			= false;
 	} else if(StringFind(Symbol(),"USDCAD")!=-1) {
		if(Max_Spread==0)Max_Spread=4;if(Risk==0.0)Risk=7.5;TakeProfit=60.0;StopLoss=60.0;
		if(GMT_Open_Hour<0.0)GMT_Open_Hour=21.0;if(GMT_Close_Hour<0.0)GMT_Close_Hour=24.0;if(GMT_Friday_Hour<0.0)GMT_Friday_Hour=16.0;
		Allow_Second_Open_Trade=false;
		Use_CCI			= true;CCI_Period=10;CCI_Entry=120;CCI_Exit=125;
		Use_WPR			= true;WPR_Period=10;WPR_Entry=90;WPR_Exit=35;
		Use_Fractals	= true;MidFractalDist=8;OppositeFractalDist=11;
		Use_ATR			= false;
		Use_MA1			= false;
		Use_MA2			= false;
		Use_MA2_Slope	= false;
		Use_MA_Dist		= false;
		Use_BB			= false;
		Use_RSI			= false;
	} else if(StringFind(Symbol(),"EURCHF")!=-1) {
		if(Max_Spread==0)Max_Spread=5;if(Risk==0.0)Risk=7.5;TakeProfit=60.0;StopLoss=40.0;
		if(GMT_Open_Hour<0.0)GMT_Open_Hour=21.0;if(GMT_Close_Hour<0.0)GMT_Close_Hour=24.0;if(GMT_Friday_Hour<0.0)GMT_Friday_Hour=16.0;
		Allow_Second_Open_Trade=false;
		Use_CCI			= true;CCI_Period=10;CCI_Entry=100;CCI_Exit=130;
		Use_WPR			= true;WPR_Period=10;WPR_Entry=91;WPR_Exit=30;
		Use_Fractals	= true;MidFractalDist=7;OppositeFractalDist=9;
		Use_ATR			= false;
		Use_MA1			= false;
		Use_MA2			= false;
		Use_MA2_Slope	= false;
		Use_MA_Dist		= false;
		Use_BB			= false;
		Use_RSI			= false;
	} else if(StringFind(Symbol(),"USDCHF")!=-1) {
		if(Max_Spread==0)Max_Spread=4;if(Risk==0.0)Risk=7.5;TakeProfit=60.0;StopLoss=40.0;
		if(GMT_Open_Hour<0.0)GMT_Open_Hour=21.0;if(GMT_Close_Hour<0.0)GMT_Close_Hour=24.0;if(GMT_Friday_Hour<0.0)GMT_Friday_Hour=16.0;
		Allow_Second_Open_Trade=false;
		Use_CCI			= true;CCI_Period=10;CCI_Entry=100;CCI_Exit=120;
		Use_WPR			= true;WPR_Period=10;WPR_Entry=91;WPR_Exit=40;
		Use_Fractals	= true;MidFractalDist=6;OppositeFractalDist=9;
		Use_ATR			= false;
		Use_MA1			= false;
		Use_MA2			= false;
		Use_MA2_Slope	= false;
		Use_MA_Dist		= false;
		Use_BB			= false;
		Use_RSI			= false;
	} else if(StringFind(Symbol(),"GBPCHF")!=-1) {
		if(Max_Spread==0)Max_Spread=6;if(Risk==0.0)Risk=7.5;TakeProfit=60.0;StopLoss=50.0;
		if(GMT_Open_Hour<0.0)GMT_Open_Hour=21.0;if(GMT_Close_Hour<0.0)GMT_Close_Hour=24.0;if(GMT_Friday_Hour<0.0)GMT_Friday_Hour=16.0;
		Allow_Second_Open_Trade=false;
		Use_CCI			= true;CCI_Period=10;CCI_Entry=100;CCI_Exit=130;
		Use_WPR			= true;WPR_Period=10;WPR_Entry=91;WPR_Exit=30;
		Use_Fractals	= true;MidFractalDist=9;OppositeFractalDist=15;
		Use_ATR			= false;
		Use_MA1			= false;
		Use_MA2			= false;
		Use_MA2_Slope	= false;
		Use_MA_Dist		= false;
		Use_BB			= false;
		Use_RSI			= false;
	} else if(StringFind(Symbol(),"GBPCAD")!=-1) {
		if(Max_Spread==0)Max_Spread=6;if(Risk==0.0)Risk=7.5;TakeProfit=60.0;StopLoss=50.0;
		if(GMT_Open_Hour<0.0)GMT_Open_Hour=21.0;if(GMT_Close_Hour<0.0)GMT_Close_Hour=24.0;if(GMT_Friday_Hour<0.0)GMT_Friday_Hour=16.0;
		Allow_Second_Open_Trade=false;
		Use_CCI			= true;CCI_Period=10;CCI_Entry=100;CCI_Exit=130;
		Use_WPR			= true;WPR_Period=10;WPR_Entry=91;WPR_Exit=30;
		Use_Fractals	= true;MidFractalDist=7;OppositeFractalDist=13;
		Use_ATR			= false;
		Use_MA1			= false;
		Use_MA2			= false;
		Use_MA2_Slope	= false;
		Use_MA_Dist		= false;
		Use_BB			= false;
		Use_RSI			= false;
	} else if(StringFind(Symbol(),"EURUSD")!=-1) {
		if(Max_Spread==0)Max_Spread=4;if(Risk==0.0)Risk=7.5;TakeProfit=60.0;StopLoss=40.0;
		if(GMT_Open_Hour<0.0)GMT_Open_Hour=21.0;if(GMT_Close_Hour<0.0)GMT_Close_Hour=24.0;if(GMT_Friday_Hour<0.0)GMT_Friday_Hour=16.0;
		Allow_Second_Open_Trade=false;
		Use_CCI			= true;CCI_Period=10;CCI_Entry=100;CCI_Exit=120;
		Use_WPR			= true;WPR_Period=8;WPR_Entry=93;WPR_Exit=42;
		Use_Fractals	= true;MidFractalDist=8;OppositeFractalDist=15;
		Use_ATR			= false;
		Use_MA1			= true;MA_Period1=75;
		Use_MA2			= true;MA_Period2=20;
		Use_MA2_Slope	= false;
		Use_MA_Dist		= false;
		Use_BB			= false;
		Use_RSI			= false;
	} else if(StringFind(Symbol(),"CADCHF")!=-1) {
		if(Max_Spread==0)Max_Spread=6;if(Risk==0.0)Risk=7.5;TakeProfit=60.0;StopLoss=50.0;
		if(GMT_Open_Hour<0.0)GMT_Open_Hour=21.0;if(GMT_Close_Hour<0.0)GMT_Close_Hour=24.0;if(GMT_Friday_Hour<0.0)GMT_Friday_Hour=16.0;
		Allow_Second_Open_Trade=false;
		Use_CCI			= true;CCI_Period=10;CCI_Entry=100;CCI_Exit=130;
		Use_WPR			= true;WPR_Period=10;WPR_Entry=91;WPR_Exit=30;
		Use_Fractals	= true;MidFractalDist=7;OppositeFractalDist=13;
		Use_ATR			= false;
		Use_MA1			= false;
		Use_MA2			= false;
		Use_MA2_Slope	= false;
		Use_MA_Dist		= false;
		Use_BB			= false;
		Use_RSI			= false;
	} else if(StringFind(Symbol(),"GBPUSD")!=-1) {
		if(Max_Spread==0)Max_Spread=4;if(Risk==0.0)Risk=7.5;TakeProfit=60.0;StopLoss=40.0;
		if(GMT_Open_Hour<0.0)GMT_Open_Hour=21.0;if(GMT_Close_Hour<0.0)GMT_Close_Hour=24.0;if(GMT_Friday_Hour<0.0)GMT_Friday_Hour=16.0;
		Allow_Second_Open_Trade=false;
		Use_CCI			= true;CCI_Period=10;CCI_Entry=100;CCI_Exit=125;
		Use_WPR			= true;WPR_Period=12;WPR_Entry=90;WPR_Exit=38;
		Use_Fractals	= true;MidFractalDist=6;OppositeFractalDist=11;
		Use_ATR			= false;
		Use_MA1			= false;
		Use_MA2			= false;
		Use_MA2_Slope	= false;
		Use_MA_Dist		= false;
		Use_BB			= false;
		Use_RSI			= false;
	} else {
		Print("WARNING: Unsupported instrument, using manual defaults.");
		return(false);
	}
	
	return(true);
}

