This is the classic MACD crossover strategy with the combined moving average trend filter. Use the tutorial as the basis for building your own trading robot.

This video uses classes developed in my earlier video “Use Common Classes to Write MQL4 and MQL5 Experts”.

The key functions used are shown below, the video will explain how these are used as part of the expert.

To use the indicator classes include these lines before any code

//	Include the indicator classes
#include <Orchard/Indicators/IndicatorMA.mqh>
CIndicatorMA	MA(Symbol(), Period(), InpMAPeriod, InpMAMethod, InpMAAppliedPrice);

#include <Orchard/Indicators/IndicatorMACD.mqh>
CIndicatorMACD	MACD(Symbol(), Period(), InpMACDFastPeriod, InpMACDSlowPeriod, InpMACDSignalPeriod, InpMACDAppliedPrice);

For MQL5 you will also need to include thse lines at the beginning of your code

//	For MQL5 use the CTrade class
//	This is a candidate for the modular approach soon
#include			<Trade/Trade.mqh>
CTrade			Trade;
CPositionInfo	PositionInfo;

and then initialise the Trade object

Trade.SetExpertMagicNumber(InpMagicNumber);

Then most of the work happens in the OnTick function

void OnTick() {

	//	Some general get out early conditions
	if (!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) return;	//	exit if expert trading is not allowed
	if (!MQLInfoInteger(MQL_TRADE_ALLOWED)) return;
	if (!AccountInfoInteger(ACCOUNT_TRADE_EXPERT)) return;
	if (!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED)) return;
	if (!NewBar())	return;													//	Only trade once per bar
	if (TradeCount()>0)	return;											//	Only trade if there are no current trades open
	
	//	Grab the relevant values
	double	ma	=	MA.GetValue(1);										//	A single value
	double	close	=	iClose(Symbol(), Period(), 1);
	double	macd[];															//	Use macd and signal to get arrays of 3 elements
	double	signal[];
	int	count	=	MACD.GetArray(0, 0, 3, macd);						//	Get 3 to make index less confusing
	if (count<3) return;														//	Not enough data, did not return 3 values
	count			=	MACD.GetArray(1, 0, 3, signal);
	if (count<3) return;														//	Should not happen if the first call worked
	
	//	Now check for trades
	if (	close>ma
			&& macd[1]<0
			&& macd[1]>signal[1]
			&& macd[2]<=signal[2] ) {	//	Buy
		OpenTrade(ORDER_TYPE_BUY);
	}
	
	if (	close<ma
			&& macd[1]>0
			&& macd[1]<signal[1]
			&& macd[2]>=signal[2] ) {	//	Sell
		OpenTrade(ORDER_TYPE_SELL);
	}
	
}

The OpenTrade function has common code to setting prices and calls a small function then specific to opening trades on each platform

void	OpenTrade(ENUM_ORDER_TYPE type) {

	double	price	=	(type==ORDER_TYPE_BUY) ? SymbolInfoDouble(Symbol(), SYMBOL_ASK) : SymbolInfoDouble(Symbol(), SYMBOL_BID);
	price				=	NormalizeDouble(price, Digits());
	double	sl		=	NormalizeDouble(SwingPrice(type), Digits());
	double	tp		=	NormalizeDouble(price + ((price-sl)*InpRatio), Digits());
	
	if (!VersionOpenTrade(type, price, sl, tp)) {
		PrintFormat("Error %i placing order type %s", GetLastError(), EnumToString(type));
	}

}

The SwingPrice function will find the most recent swing high or low

double	SwingPrice(ENUM_ORDER_TYPE type) {

	//	init the variables
	int	bar	=	0;
	double	price	=	0;

	if (type==ORDER_TYPE_BUY) {
		bar	=	iLowest(Symbol(), Period(), MODE_LOW, InpSwingLookback, 1);	//	First just find lowest for the period
		price	=	iLow(Symbol(), Period(), bar);
		while (price>=iLow(Symbol(), Period(), ++bar)) {	//	Now keep moving back as long as next bar is lower
			price	=	iLow(Symbol(), Period(), bar);
		}
	} else {	//	Sell is just opposite to buy
		bar	=	iHighest(Symbol(), Period(), MODE_HIGH, InpSwingLookback, 1);
		price	=	iHigh(Symbol(), Period(), bar);
		while (price<=iHigh(Symbol(), Period(), ++bar)) {
			price	=	iHigh(Symbol(), Period(), bar);
		}
	}	

	return(price);

}