//+------------------------------------------------------------------+
//|                                                     	   TPI Test |
//|                                                    Andriy Moraru |
//|                                         http://www.earnforex.com |
//|            							                            2011 |
//+------------------------------------------------------------------+
#property copyright "www.EarnForex.com, 2011"
#property link      "http://www.earnforex.com"
#property version   "1.0"

#property description "Tests the EA based on TPI with trailing stop."

#include <Trade/Trade.mqh>
#include <Trade/PositionInfo.mqh>

#define LONG 1
#define SHORT 2

input int StopLoss = 100; // Isn't used
input int TakeProfit = 0; // 0 means that it won't be set
input int ATRM = 3;
input int Slippage = 100; 	// Tolerated slippage in pips, pips are fractional
input int Lookback = 45; // TPI input parameter
input int ContractSize = 100000; // Contract size for a fractional position sizing

input double iLots = 0.1;

// Main trading objects
CTrade *Trade;
CPositionInfo PositionInfo;

// Global variables
bool HaveLongPosition;
bool HaveShortPosition;
ulong LastBars = 0;
double SL, TP;
int LastPosition = 0;
int CurTrend = 0;
int handle, myATR;
double Lots = 0;

//+------------------------------------------------------------------+
//| Expert Initialization Function                                   |
//+------------------------------------------------------------------+
void OnInit()
{
	// Initialize the Trade class object
	Trade = new CTrade;
	Trade.SetDeviationInPoints(Slippage);
   handle = iCustom(NULL, 0, "TotalPowerIndicator\\TotalPowerIndicator", Lookback, 24);
   myATR = iATR(NULL, 0, 24);
}

//+------------------------------------------------------------------+
//| Expert Deinitialization Function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
	delete Trade;
}

//+------------------------------------------------------------------+
//| Expert Every Tick Function                                       |
//+------------------------------------------------------------------+
void OnTick()
{
	if (TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) == false) return;
	
   // Getting the ATR values
   double ATR[1];
   double Bear[1];
   double Bull[1];
   //ArraySetAsSeries(ATR, true);
   if (CopyBuffer(myATR, 0, 0, 1, ATR) != 1) return;
   // ATR-based position sizing.
	Lots = NormalizeDouble(0.01 * AccountInfoDouble(ACCOUNT_BALANCE) / (ATR[0] * ContractSize), 1);
	
   ATR[0] *= ATRM;

   if (ATR[0] <= (SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL) + SymbolInfoInteger(Symbol(), SYMBOL_SPREAD)) * _Point) ATR[0] = (SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL) + SymbolInfoInteger(Symbol(), SYMBOL_SPREAD)) * _Point;

  	// Check what position is currently open
 	GetPositionStates();
   
 	// Adjust SL and TP of the current position
 	if ((HaveLongPosition) || (HaveShortPosition)) AdjustSLTP(ATR[0]);

   if (Bars(NULL, 0) == LastBars) return;
   LastBars = Bars(NULL, 0);

   if (CopyBuffer(handle, 1, 1, 1, Bear) != 1) return;
   if (CopyBuffer(handle, 2, 1, 1, Bull) != 1) return;

   if (Bull[0] > Bear[0])
   {
      if (CurTrend == -1) fBuy(ATR[0]);
      CurTrend = 1;
   } 
   else if (Bull[0] < Bear[0])
   {
      if (CurTrend == 1) fSell(ATR[0]);
      CurTrend = -1;
   }
}

void fBuy(double ATR)
{
   double Ask, Bid;
   
   ClosePrevious();

  	for (int i = 0; i < 10; i++)
  	{
  	  	Ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
  		Bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);

  		// Bid and Ask are swapped to preserve the probabilities and decrease/increase profit/loss size
  	  	SL = NormalizeDouble(Bid - ATR, _Digits);
  	  	if (TakeProfit) TP = NormalizeDouble(Bid + TakeProfit * _Point, _Digits);
  	  	else TP = 0;
  		Trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, Lots, Ask, SL, TP);
  		Sleep(1000);
  		if ((Trade.ResultRetcode() != 10008) && (Trade.ResultRetcode() != 10009) && (Trade.ResultRetcode() != 10010))
  			Print("Long Position Open Return Code: ", Trade.ResultRetcodeDescription());
  		else return;
  	}
}

void fSell(double ATR)
{
   double Ask, Bid;
   
   ClosePrevious();

   for (int i = 0; i < 10; i++)
  	{
  	  	Ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
  		Bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);

  		// Bid and Ask are swapped to preserve the probabilities and decrease/increase profit/loss size
  	   SL = NormalizeDouble(Ask + ATR, _Digits);
		if (TakeProfit) TP = NormalizeDouble(Ask - TakeProfit * _Point, _Digits);
		else TP = 0;
		Trade.PositionOpen(_Symbol, ORDER_TYPE_SELL, Lots, Bid, SL, TP);
		Sleep(1000);
		if ((Trade.ResultRetcode() != 10008) && (Trade.ResultRetcode() != 10009) && (Trade.ResultRetcode() != 10010))
			Print("Short Position Open Return Code: ", Trade.ResultRetcodeDescription());
		else return;
	}
}

//+------------------------------------------------------------------+
//| Check What Position is Currently Open										|
//+------------------------------------------------------------------+
void GetPositionStates()
{
	// Is there a position on this currency pair?
	if (PositionInfo.Select(_Symbol))
	{
		if (PositionInfo.PositionType() == POSITION_TYPE_BUY)
		{
			HaveLongPosition = true;
			HaveShortPosition = false;
		}
		else if (PositionInfo.PositionType() == POSITION_TYPE_SELL)
		{ 
			HaveLongPosition = false;
			HaveShortPosition = true;
		}
   	if (HaveLongPosition) LastPosition = LONG;
   	else if (HaveShortPosition) LastPosition = SHORT;
	}
	else 
	{
		HaveLongPosition = false;
		HaveShortPosition = false;
	}
}

//+------------------------------------------------------------------+
//| Close Open Position																|
//+------------------------------------------------------------------+
void ClosePrevious()
{
	for (int i = 0; i < 10; i++)
	{
		Trade.PositionClose(_Symbol, Slippage);
		if ((Trade.ResultRetcode() != 10008) && (Trade.ResultRetcode() != 10009) && (Trade.ResultRetcode() != 10010))
			Print("Position Close Return Code: ", Trade.ResultRetcodeDescription());
		else return;
	}
}

//+------------------------------------------------------------------+
//| Adjust Stop-Loss and TakeProfit of the Open Position					|
//+------------------------------------------------------------------+
void AdjustSLTP(double SLparam)
{
	// Is there a position on this currency pair?
	if (PositionInfo.Select(_Symbol))
	{
		if (PositionInfo.PositionType() == POSITION_TYPE_BUY)
		{
		   double Bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
			SL = NormalizeDouble(Bid - SLparam, _Digits);
			TP = NormalizeDouble(PositionInfo.TakeProfit(), _Digits);
			if (SL > NormalizeDouble(PositionInfo.StopLoss(), _Digits))
			{
				for (int i = 0; i < 10; i++)
				{
					Trade.PositionModify(_Symbol, SL, TP);
					if ((Trade.ResultRetcode() != 10008) && (Trade.ResultRetcode() != 10009) && (Trade.ResultRetcode() != 10010))
						Print("Long Position Modify Return Code: ", Trade.ResultRetcodeDescription());
					else return;
				}
			}
		}
		else if (PositionInfo.PositionType() == POSITION_TYPE_SELL)
		{ 
			double Ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
			SL = NormalizeDouble(Ask + SLparam, _Digits);
			TP = NormalizeDouble(PositionInfo.TakeProfit(), _Digits);
			if (SL < NormalizeDouble(PositionInfo.StopLoss(), _Digits))
			{
				for (int i = 0; i < 10; i++)
				{
					Trade.PositionModify(_Symbol, SL, TP);
					if ((Trade.ResultRetcode() != 10008) && (Trade.ResultRetcode() != 10009) && (Trade.ResultRetcode() != 10010))
						Print("Short Position Modify Return Code: ", Trade.ResultRetcodeDescription());
					else return;
				}
			}
		}
	}
}
//+------------------------------------------------------------------+

