I have covered using iCustom to make custom indicator information available in your EA several times but there is one question that keeps appearing.

If you have an indicator that actually draws signals on screen, like buy and sell arrows, how can you use that information in an EA?

It’s difficult because these indicators often do not use buffers to store data and the signal arrows on screen are just screen obejcts. iCustom does not offer any way to access this information. This video shows how to load those indicators on screen and write an EA that will read the data from the running indicator.

Warning: This is a description of the type of things to look for and 2 approaches to take. Each custom indicator is different and you will have to adapt this to fit your indicator.

The code is the same for MT4 and MT5. The code for the first expert (where the indicator creates new objects at each signal) is below

/**
 *	Object Watch
 *
 *	Copyright 2021, Orchard Forex
 *	https://orchardforex.com
 *
 */

#property copyright "Copyright 2021, Orchard Forex"
#property link      "https://orchardforex.com"
#property version   "1.00"
// for MQL4 add #property strict

string		NamePart;

int OnInit() {

	NamePart	=	"test_arrow_";

	ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, true);
	ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, true);

   return(INIT_SUCCEEDED);

}

void OnDeinit(const int reason) {


}

void OnTick() {


}

void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam) {

	//	For the first situation I know a new arrow is created for a signal
	//	Only react on new arrow
	
	//	Only on object_create
	if (id==CHARTEVENT_OBJECT_CREATE) {
		NewObject(sparam);
		return;
	}

}

void	NewObject(string name) {
	
	//	Only on name matching test_arrow_*
	if (StringSubstr(name, 0, StringLen(NamePart))!=NamePart) return;

	//	Quick check that the object exists in the correct window
	//		I'm looking at window 0
	int sub_window = ObjectFind(0, name);
	if (sub_window!=0)	return;
	
	//	Only buy arrows or sell arrows
	long type = ObjectGetInteger(0, name, OBJPROP_TYPE);
	if (type!=OBJ_ARROW_BUY && type!=OBJ_ARROW_SELL) return;

	//	Report the object found
	ReportObject("New", name);
	
}

void	ReportObject(string event, string name) {
	
	//	Now I have an object, grab some properties but what you do depends on the strategy
	datetime	object_time		=	(datetime)ObjectGetInteger(0, name, OBJPROP_TIME);
	ENUM_OBJECT	object_type	=	(ENUM_OBJECT)ObjectGetInteger(0, name, OBJPROP_TYPE);
	int		object_bar		=	iBarShift(Symbol(), Period(), object_time);
	double	object_price	=	ObjectGetDouble(0, name, OBJPROP_PRICE);
	double	bar_high			=	iHigh(Symbol(), Period(), object_bar);
	double	bar_low			=	iLow(Symbol(), Period(), object_bar);

	PrintFormat("This is where you trade on your strategy using information from the object");	
	PrintFormat("Event = %s", event);	
	PrintFormat("Object name = %s", name);
	PrintFormat("Object type = %s", EnumToString(object_type));
	PrintFormat("time=%s, bar=%i, price=%f, high=%f, low=%f", TimeToString(object_time), object_bar, object_price, bar_high, bar_low);	

}

And for version 2 (where the indicator moves signals to new positions)

/**
 *	Object Watch v2
 *
 *	Copyright 2021, Orchard Forex
 *	https://orchardforex.com
 *
 */

#property copyright "Copyright 2021, Orchard Forex"
#property link      "https://orchardforex.com"
#property version   "1.00"
// for MQL4 add #property strict

struct SObjectInfo {
	string	name;
	int		type;
	datetime	time;
	double	price;
};

SObjectInfo	Objects[];
string		NamePart;

int OnInit() {

	NamePart	=	"test_arrow_";
	ArrayResize(Objects, 0);
	LoadObjects(OBJ_ARROW_BUY);
	LoadObjects(OBJ_ARROW_SELL);

	ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, true);
	ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, true);

   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason) {


}

void OnTick() {

	string name = HasChanged();
	if (name!="") {
		ReportObject("Changed", name);
		AddObject(name);
	}

}

void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam) {

	//	For the first situation I know a new arrow is created for a signal
	//	Only react on new arrow
	
	//	Only on object_create or delete
	if (id==CHARTEVENT_OBJECT_CREATE) {
		NewObject(sparam);
		return;
	}
	
	if (id==CHARTEVENT_OBJECT_DELETE) {
		DeleteObject(sparam);
		return;
	}

	return;
	
}

void	LoadObjects(long type) {

	int	count	=	ObjectsTotal(0, 0, type);
	for (int i=0; i<count; i++) {
		string name = ObjectName(0, i, 0, type);
		NewObject(name);
	}

}

void	NewObject(string name, bool takeAction=true) {
	
	if (StringSubstr(name, 0, StringLen(NamePart))!=NamePart) return;
	
	//	Quick check that the object exists in the correct window
	//		I'm looking at window 0
	int sub_window = ObjectFind(0, name);
	if (sub_window!=0)	return;
	
	//	Only buy arrows or sell arrows
	long type = ObjectGetInteger(0, name, OBJPROP_TYPE);
	if (type!=OBJ_ARROW_BUY && type!=OBJ_ARROW_SELL) return;

	//	Add this object to the list
	AddObject(name);
	ReportObject("New", name);
	
}

void	ReportObject(string event, string name) {
	
	//	Now I have an object, grab some properties but what you do depends on the strategy
	datetime	object_time		=	(datetime)ObjectGetInteger(0, name, OBJPROP_TIME);
	ENUM_OBJECT	object_type	=	(ENUM_OBJECT)ObjectGetInteger(0, name, OBJPROP_TYPE);
	int		object_bar		=	iBarShift(Symbol(), Period(), object_time);
	double	object_price	=	ObjectGetDouble(0, name, OBJPROP_PRICE);
	double	bar_high			=	iHigh(Symbol(), Period(), object_bar);
	double	bar_low			=	iLow(Symbol(), Period(), object_bar);
	
	UpdateObject(name);

	PrintFormat("This is where you trade on your strategy using information from the object");	
	PrintFormat("Event = %s", event);	
	PrintFormat("Object name = %s", name);
	PrintFormat("Object type = %s", EnumToString(object_type));
	PrintFormat("time=%s, bar=%i, price=%f, high=%f, low=%f", TimeToString(object_time), object_bar, object_price, bar_high, bar_low);	

}

void	UpdateObject(string name) {

}

int	FindObject(string name) {

	int	index	=	ArraySize(Objects);
	for (int i=0; i<index; i++) {
		if (Objects[i].name==name) return(i);
	}
	return(-1);
	
}

void	AddObject(string name) {

	int	index	=	FindObject(name);
	if (index<0) {
		index	=	ArraySize(Objects);
		ArrayResize(Objects, index+1, 10);
	}
	Objects[index].name	=	name;
	Objects[index].type	=	(int)ObjectGetInteger(0, name, OBJPROP_TYPE);
	Objects[index].price	=	ObjectGetDouble(0, name, OBJPROP_PRICE);
	Objects[index].time	=	(datetime)ObjectGetInteger(0, name, OBJPROP_TIME);

}

void	DeleteObject(string name) {

	int	index	=	FindObject(name);
	if (index>=0) {
		int	count	=	ArraySize(Objects);
		for (int i=index; i<(count-1); i++) {
			Objects[i] = Objects[i+1];
		}
		ArrayResize(Objects, count-1);
		PrintFormat("Object deleted %s", name);
	}
	
}

string	HasChanged() {

	int	count	=	ArraySize(Objects);
	for (int i=0; i<count; i++) {
		if (ObjectHasChanged(i)) return(Objects[i].name);
	}
	
	return("");
	
}
	
bool		ObjectHasChanged(int index) {

	string name = Objects[index].name;
	if (Objects[index].type != ObjectGetInteger(0, name, OBJPROP_TYPE)) return(true);
	if (Objects[index].price != ObjectGetDouble(0, name, OBJPROP_PRICE)) return(true);
	if (Objects[index].time != (datetime)ObjectGetInteger(0, name, OBJPROP_TIME)) return(true);
	
	return(false);
	
}


Leave a Reply