//=============================================================================
//                                                     Fluid Turquoise 3.4.mq4 
//                                                                 Derk Wehler 
//                                                            fibofx@gmail.com
//
// Taken from FB3.3 by Matt Pavlovich: fibofx@gmail.com.  
// One change made by Derk Wehler, suggested by TradeForexFx: The use of the 
// difference of two moving averages instead of the accelorator oscillator.
// Search for "TradeForexFx" to find changes.
//
// Robert Hill
//  1/11/2007
// Added automatic calculation of MagicNumber using Symbol and Timeframe of chart 
// so that this can be tested on any currency pair and timeframe
// version 1.1 1/12/07
// added code to select AC or MA indicator  
// Changed code where OrdersTotal() was used instead of total
// Added functions for GetStopLoss, GetTakeProfit, GetTrailingStop
//
// Replaced 0 timeframe with Period_H4 for backtesting on lower timeframes
// I think this might give more accurate results
//
// Added MAdif to use values other than 1 for difference
//
// Added MaxSpread as input so other pairs can be tested
//
// Changed the following from comment in forum about using < 0 and > 0 in double down etc
// Modified to use testBuy and testSell instead of 0 and 1
// especially in code for double down etc where 0 was used
// This now reflects better use of MA
// Added single value for risk as a form of money management
// Modified formulas to use riskm, riskM and riskS divisor
// to achieve same values for old riskm, riskM and riskS
// Made more modular for easier understanding of code 
//
// version 1.2
// Removed some change line comments for easier reading of code
//=============================================================================

#property copyright "Matt Pavlovich"
#property link      "fibofx@gmail.com"
#include <stdlib.mqh>
#include <stderror.mqh>

// Robert Added UseAC to determine which works better AC or MA
extern int       UseAC        = 1;   // 1 use AC, 0 use MA    
extern int       MAdif        = 1;
extern int       MaxSpread    = 3;   // 3 for EURUSD
extern double    MinTime 		= 120;
extern double    drawdown1		= 10;
extern double    drawdown2		= 20;
extern double    drawdown3		= 30;
extern double    MaxLots		= 100;
extern double    stop 			= 1;//1 - 4hr//
extern double    profit 		= 3;//3 - 4hr//
extern double    trailer 		= 0.5;
// Line introduced to have desirable profit target for each trade
extern double    PipProfit 		= 4;
extern bool      DoubleDown 	= true;
extern bool      TrippleDown 	= true;
extern bool      QuadDown 		= true;
extern bool      Reverse 		= false;
extern bool      micro 			= true;
extern bool      mini 			= false;
extern bool      standard 		= false;

/*
// Robert modified for a form of money management
double    riskm = 75;	// micro=75, mini=7.5, standard=.75 //
double    riskM = 7.5;	// micro=75, mini=7.5, standard=.75 //
double    riskS = 0.75;	// micro=75, mini=7.5, standard=.75 //
*/
extern double risk   = 75;
double        riskm  = 100000.0; 	// micro=75, mini=7.5, standard=.75 //
double        riskM  = 1000000.0;	// micro=75, mini=7.5, standard=.75 //
double        riskS  = 10000000.0;	// micro=75, mini=7.5, standard=.75 //

double           Lots;
// int              MagicNumber = 333; - original line
// Modified to calculate MagicNumber in Init by Robert
extern int  MagicBase = 3000; 
int         MagicNumber;

//This is a reverse Martingale system.  It trades with the trend, doubling down as the 
// position goes against you.  It is an "Always in Play" system as well, so be ready 
// to place a lot of trades!

//PLACE ON EURUSD 4HR CHART.  YOU MUST HAVE AT LEAST $500 TO START WITH A MICRO ACCOUNT, 
// $5000 FOR A MINI, AND $50,000 FOR A STANDARD ACCOUNT. THIS SYSTEM HAS NOT YET BEEN 
// TESTED.  AS SUCH, DEMO TEST BEFORE GOING LIVE.  AS ALWAYS, SPECULATING IN FOREX AND 
// ANY OTHER MARKETS IS RISKY.  YOU COULD LOOSE EVERY CENT YOU HAVE.  BE SMART!  ALSO, 
// USE ONLY WITH A BROKER WITH A 2 PIP SPREAD ON THE EURUSD, AS WELL AS A VOLATILE FEED.
// THE LATTER DOES NOT INCLUDE THE LIKES OF INTERBANK FX, ALPARI, ETC.  THERE IS NOTHING 
// WRONG WITH THESE BROKERS, BUT THEIR FEEDS TEND TO BE LESS VOLATILE THAN THEIR 
// COMPETITORS.  I PERSONALLY RECOMMEND VELOCITY4X.  I AM NOT AN IB.  HAPPY TRADING!

//-------------------------------------------------------------
// expert initialization function
//-------------------------------------------------------------
int init()
{
   MagicNumber = MagicBase + func_Symbol2Val(Symbol())*100 + func_TimeFrame_Const2Val(Period());
}
   
//-------------------------------------------------------------
//   GetEntrySignal
//
//  Get entry signal to place trades
//
// Change made for TradeForexFx to use moving average instead of iAC:
// myao = iAC(Symbol(), 0, 0);	// original line
// Change made to select either AC or MA by Robert
//-------------------------------------------------------------
double GetEntrySignal()
{
  double signal;
	
   if (UseAC == 1)
      signal = iAC(Symbol(), PERIOD_H4, 0);
   else
	   signal = (iMA(NULL, PERIOD_H4, 5, 0, MODE_LWMA, PRICE_CLOSE, 0) - 
			iMA(NULL, PERIOD_H4, 8, 0, MODE_LWMA, PRICE_CLOSE, 0)) / Point;
			
	return(signal);
}

//=============================================================================
// Start
//=============================================================================
int start()
{

	int cnt, ticket, myTotal, testBuy, testSell;
	double TrailingStop;
	double msd, myrsi, myao;

	if (Lots > MaxLots) 
		Lots = MaxLots;
	if (Lots >= 100)
		Alert("Take your profits and run!!  Your broker will not allow more than 100 lots!  You cannot double down from here!  Stop trading!");

   Lots = GetLots();
   
   myao = GetEntrySignal();
			
	if (!IsTesting()) 
		Comment(" TrailingStop=", DoubleToStr(TrailingStop, 4));
		
	
   if (UseAC == 1)
   {
     testBuy = 0;
     testSell = 0;
   }
   else
   {
     testBuy = MAdif;
     testSell = -MAdif;
   }
   
	myTotal = GetTotalOpenOrders();

   switch (myTotal)
   {
      case 0 :
            if (SpreadOK())
            {
               if (myao > testBuy) PlaceOrder(OP_BUY, Lots);
               if (myao < testSell) PlaceOrder(OP_SELL, Lots);
            }
            break;
              
      case 1 : if (DoubleDown)
               {
                  if (SpreadOK())
                  {
                     if (OrderOpenPrice() - Ask >= drawdown1 * Point && myao > testBuy) PlaceOrder(OP_BUY, Lots*2);
                     if (Bid - OrderOpenPrice() >= drawdown1 * Point && myao < testSell) PlaceOrder(OP_SELL, Lots*2);
                  }
               }
         break;
      case 2 : if (TrippleDown)
               {
                  if (SpreadOK())
                  {
                     if (OrderOpenPrice() - Ask >= drawdown2 * Point && myao > testBuy) PlaceOrder(OP_BUY, Lots*4);
                     if (Bid - OrderOpenPrice() >= drawdown2 * Point && myao < testSell) PlaceOrder(OP_SELL, Lots*4);
                  }
               }
          break;
		
   	case 3 : if (QuadDown)
               {
                  if (SpreadOK())
                  {
                     if (OrderOpenPrice() - Ask >= drawdown3 * Point && myao > testBuy) PlaceOrder(OP_BUY, Lots*8);
                     if (Bid - OrderOpenPrice() >= drawdown3 * Point && myao < testSell) PlaceOrder(OP_SELL, Lots*8);
                  }
               }
	}
       
	myTotal = GetTotalOpenOrders();
	for(cnt=myTotal-1; cnt >= 0; cnt--)
	{
		OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);

		if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
		{
//			TrailingStop = iATR(Symbol(), PERIOD_H4, 14, 1) * trailer;  - line changed by Robert
			TrailingStop = GetTrailingStop();
			if (TrailingStop <= 0.0005) 
				TrailingStop=0.0006;
				
			if (OrderType() == OP_BUY)   // long position is opened //
			{
//	if ((Bid - OrderOpenPrice() >= 4 * Point && CurTime() - OrderOpenTime() >= MinTime)) - original line
				if ((Bid - OrderOpenPrice() >= PipProfit * Point && CurTime() - OrderOpenTime() >= MinTime))
				{
					RefreshRates();
					OrderClose(OrderTicket(), OrderLots(), Bid, 1, Violet); // close position
					return(0); // exit
				}
				if (Reverse)
//					if (myao < 0)  - line changed by Robert
					if (myao < testSell)
					{
						RefreshRates();
						OrderClose(OrderTicket(), OrderLots(), Bid, 1, Violet); // close position
						return(0); // exit
					}
					
				// check for trailing stop
				if (TrailingStop > 0)  
				{                 
					if (Bid - OrderOpenPrice() > TrailingStop)
					{
						if (OrderStopLoss() < Bid - TrailingStop)
						{
							RefreshRates();
							OrderModify(OrderTicket(), OrderOpenPrice(), Bid - TrailingStop, OrderTakeProfit(), 0, Blue);
						}
					}
				}
			}

			if (OrderType() == OP_SELL)   // short position is opened //
			{
				
//				if ((OrderOpenPrice() - Ask >= 4 * Point && CurTime() - OrderOpenTime() >= MinTime))- original line
				if ((OrderOpenPrice() - Ask >=  PipProfit * Point && CurTime() - OrderOpenTime() >= MinTime))
				{
					RefreshRates();
					OrderClose(OrderTicket(), OrderLots(), Ask, 1, Violet); // close position
					return(0); // exit
                }
				if (Reverse)
//					if (myao > 0)  - line changed by Robert
					if (myao > testBuy)
					{
						RefreshRates();
						OrderClose(OrderTicket(), OrderLots(), Ask, 1, Violet); // close position
						return(0); // exit
					}
				// check for trailing stop
				if (TrailingStop > 0)  
				{
					if ((OrderOpenPrice() - Ask) > (TrailingStop))
					{
						if ((OrderStopLoss() > (Ask + TrailingStop)) || (OrderStopLoss() == 0))
						{
							RefreshRates();
							OrderModify(OrderTicket(), OrderOpenPrice(), Ask + TrailingStop, OrderTakeProfit(), 0, Red);
						}
					}
				}
			}
		}
	}
}

void PlaceOrder(int cmd, double mLots)
{
   int err, ticket;
   double SL, TP;

   if (cmd == OP_BUY)
   {
//		SL = Ask - iATR(Symbol(), PERIOD_H4, 14, 0) * stop;  - line changed by Robert
//		TP = Ask + iATR(Symbol(), PERIOD_H4, 14, 0) * profit;  - line changed by Robert
      SL = GetStopLoss(OP_BUY);
      TP = GetTakeProfit(OP_BUY);
		ticket = OrderSend(Symbol(), OP_BUY, mLots, Ask, 1, SL, TP, "", MagicNumber, 0, Blue);
		if (ticket > 0)
		{
			if (OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) 
			{
				Print("BUY order opened : ", OrderOpenPrice());
			}
		}
		else 
		{
			err = GetLastError(); 
         Print("Error opening BUY order : (" + err + ") " + ErrorDescription(err));
		}
	}
	
	if (cmd == OP_SELL)
	{
//		SL = Bid + iATR(Symbol(), PERIOD_H4, 14, 0) * stop;  - line changed by Robert
//		TP = Bid - iATR(Symbol(), PERIOD_H4, 14, 0) * profit;  - line changed by Robert
      SL = GetStopLoss(OP_SELL);
      TP = GetTakeProfit(OP_SELL);
		ticket = OrderSend(Symbol(), OP_SELL, mLots, Bid, 1, SL, TP, "", MagicNumber, 0, Red);
		if (ticket > 0)
		{
			if (OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES)) 
			{
				Print("SELL order opened : ", OrderOpenPrice());
			}
		}
		else 
		{
			err = GetLastError(); 
         Print("Error opening SELL order : (" + err + ") " + ErrorDescription(err));
		}
	}
}	

//-------------------------------------------------------------
// GetTotalOpenOrders
//
// Get total number of orders open for this ea
//-------------------------------------------------------------
int GetTotalOpenOrders()
{
   int cnt, total;
   
	total = 0; 
	for (cnt=OrdersTotal()-1; cnt >= 0; cnt--)
	{
		OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
		
		if (OrderSymbol() != Symbol()) continue;
		if (OrderMagicNumber() != MagicNumber)	continue;
			
		if (OrderType() == OP_BUY)		total++;
		if (OrderType() == OP_SELL)	total++;
	}
	
	return (total);
}

//-------------------------------------------------------------
// SpreadOK
//
// Check if spread is smaller then Maximum spread allowed
//-------------------------------------------------------------
bool SpreadOK()
{
   if (Ask - Bid <= MaxSpread * Point) return(true);
   return(false);
}

//-------------------------------------------------------------
//  GetLots
// Modified by Robert for money management
//	if (micro)
//		Lots = MathCeil(AccountEquity() * riskm / 100000) / 100;
//
//	if (mini)
//		Lots = MathCeil(AccountEquity() * riskM / 100000) / 10;
//
//	if (standard)
//		Lots = MathCeil(AccountEquity() * riskS / 100000);
//-------------------------------------------------------------
double GetLots()
{

   double mLots;
   if (micro)
		mLots = MathCeil(AccountEquity() * risk / riskm) / 100;

	if (mini)
		mLots = MathCeil(AccountEquity() * risk / riskM) / 10;

	if (standard)
		mLots = MathCeil(AccountEquity() * risk / riskS);
		
	return(mLots);
   
}
//-------------------------------------------------------------
// GetStopLoss
//
// Uses original formula in a function
// so easier changes can be made
//
//-------------------------------------------------------------
double GetStopLoss(int cmd)
{
   double mySL;
   
   if (cmd == OP_BUY)
   	mySL = Ask - iATR(Symbol(), PERIOD_H4, 14, 0) * stop;
   else
		mySL = Bid + iATR(Symbol(), PERIOD_H4, 14, 0) * stop;
		
	return(mySL);
   
}

//-------------------------------------------------------------
// GetTakeProfit
//
// Uses original formula in a function
// so easier changes can be made
//
//-------------------------------------------------------------
double GetTakeProfit(int cmd)
{
   double myTP;
   
   if (cmd == OP_BUY)
		myTP = Ask + iATR(Symbol(), PERIOD_H4, 14, 0) * profit;
   else
		myTP = Bid - iATR(Symbol(), PERIOD_H4, 14, 0) * profit;
	
	return(myTP);
   
}

//-------------------------------------------------------------
// GetTrailingStop
//
// Uses original formula in a function
// so easier changes can be made
//
//-------------------------------------------------------------
double GetTrailingStop()
{
   double myTS;
   
   myTS = iATR(Symbol(), PERIOD_H4, 14, 1) * trailer;
	return(myTS);
}

//-------------------------------------------------------------
// Time frame interval appropriation  function
//-------------------------------------------------------------
int func_TimeFrame_Const2Val(int Constant )
{
   switch(Constant)
   {
      case 1 :     return(1); // M1
      case 5 :     return(2); // M5
      case 15 :    return(3);
      case 30 :    return(4);
      case 60 :    return(5);
      case 240 :   return(6);
      case 1440 :  return(7);
      case 10080 : return(8);
      case 43200 : return(9);
   }
}

//-------------------------------------------------------------
// Convert symbol to number for calculation of magic number
//-------------------------------------------------------------
int func_Symbol2Val(string symbol)
{
   string mySymbol = StringSubstr(symbol,0,6);
   
	if(mySymbol=="AUDCAD") return(1);
	if(mySymbol=="AUDJPY") return(2);
	if(mySymbol=="AUDNZD") return(3);
	if(mySymbol=="AUDUSD") return(4);
	if(mySymbol=="CHFJPY") return(5);
	if(mySymbol=="EURAUD") return(6);
	if(mySymbol=="EURCAD") return(7);
	if(mySymbol=="EURCHF") return(8);
	if(mySymbol=="EURGBP") return(9);
	if(mySymbol=="EURJPY") return(10);
	if(mySymbol=="EURUSD") return(11);
	if(mySymbol=="GBPCHF") return(12);
	if(mySymbol=="GBPJPY") return(13);
	if(mySymbol=="GBPUSD") return(14);
	if(mySymbol=="NZDUSD") return(15);
	if(mySymbol=="USDCAD") return(16);
	if(mySymbol=="USDCHF") return(17);
	if(mySymbol=="USDJPY") return(18);
	Comment("unexpected Symbol");
	return(19);
}

  