//+------------------------------------------------------------------+
//|                                                 TradeContext.mq4 |
//|                                      Copyright © 2006, komposter |
//|                                      mailto:komposterius@mail.ru |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, komposter"
#property link      "mailto:komposterius@mail.ru"

/////////////////////////////////////////////////////////////////////////////////
/**/ int _IsTradeAllowed( int MaxWaiting_sec = 30 )
/////////////////////////////////////////////////////////////////////////////////
// функция определяет состояние торгового потока. Коды возвратов:
//  1 - торговый поток свободен, можно торговать
//  0 - торговый поток был занят, но освободился. Торговать можно только после обновления рыночной информации.
// -1 - торговый поток занят, ожидание прервано пользователем (эксперт удалён с графика, закрыт терминал, изменился 
// 	  период и/или символ графика, ... )
// -2 - торговый поток занят, истекло максимальное время ожидания (MaxWaiting_sec). Возможно, эксперту запрещена 
// 	  торговля (галочка "Разрешить эксперту торговать" в настройках эксперта).
//
// MaxWaiting_sec - время (в секундах), в течении которого функция будет ждать освобождения торгового потока (если он 
// занят). По умолчанию = 30.
/////////////////////////////////////////////////////////////////////////////////
{
	// проверяем, свободен ли торговый поток
	if ( !IsTradeAllowed() )
	{
		int StartWaitingTime = GetTickCount();
		Print( "Торговый поток занят! Ждём, пока он освободиться..." );
		// бесконечный цикл
		while ( true )
		{
			// если эксперт был остановлен пользователем, прекращаем работу
			if ( IsStopped() ) { Print( "Эксперт был остановлен пользователем!" ); return(-1); }
			// если ожидание длится дольше времени, указанного в переменной MaxWaiting_sec, тоже прекращаем работу
			if ( GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000 ) { Print( "Превышен лимит ожидания (" + MaxWaiting_sec + " сек.)!" ); return(-2); }
			// если торговый поток освободился,
			if ( IsTradeAllowed() )
			{
				Print( "Торговый поток освободился!" );
				return(0);
			}
			// если ни одно из условий остановки цикла не сработало, "ждём" 0,1 секунды и начинаем проверку сначала
			Sleep(100);
		}
	}
	else
	{
		Print( "Торговый поток свободен!" );
		return(1);
	}
}
/*
Шаблон эксперта, использующего функцию _IsTradeAllowed:
int start()
{
	// определяем необходимость входа в рынок
	...
	// расчитываем уровни Стоп Лосс, Тейк Профит и размер лота
	...
	// проверяем, свободен ли торговый поток
	int TradeAllow = _IsTradeAllowed();
	if ( TradeAllow < 0 ) { return(-1); }
	if ( TradeAllow == 0 )
	{
		RefreshRates();
		// пересчитываем уровни Стоп Лосс и Тейк Профит
		...
	}
	// открываем позицию
	OrderSend(.....);
return(0);
}
*/

/////////////////////////////////////////////////////////////////////////////////
/**/ int TradeIsBusy ( int MaxWaiting_sec = 30 )
/////////////////////////////////////////////////////////////////////////////////
// Функция меняет значение глобальной переменной TradeIsBusy с 0 на 1.
// Если в момент запуска TradeIsBusy = 1, функция ждёт, пока TradeIsBusy станет = 0, и только потом меняет.
// Если глобальной переменной TradeIsBusy не существует, функция создаёт её.
// Коды возвратов:
//  1 - успешное завершение. Глобальной переменной TradeIsBusy присвоено значение 1
// -1 - в момент запуска функции TradeIsBusy = 1, ожидание было прервано пользователем (эксперт удалён с графика, закрыт 
// терминал, изменился период и/или символ графика, ... )
// -2 - в момент запуска функции TradeIsBusy = 1, истекло максимальное время ожидания (MaxWaiting_sec)
/////////////////////////////////////////////////////////////////////////////////
{
	// при тестировании нет смысла в разделении торгового потока - просто завершаем работу функции
	if ( IsTesting() ) { return(1); }
	int _GetLastError = 0, StartWaitingTime = GetTickCount();

	//+------------------------------------------------------------------+
	//| Проверяем, существует ли гл. переменная и, если нет, создаём её
	//+------------------------------------------------------------------+
	while( true )
	{
		// если эксперт был остановлен пользователем, прекращаем работу
		if ( IsStopped() ) { Print( "Эксперт был остановлен пользователем!" ); return(-1); }
		// если ожидание длится дольше времени, указанного в переменной MaxWaiting_sec, тоже прекращаем работу
		if ( GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000 ) { Print( "Превышен лимит ожидания (" + MaxWaiting_sec + " сек.)!" ); return(-2); }
		// проверяем, существует ли гл. переменная
		if ( GlobalVariableCheck( "TradeIsBusy" ) )
		// если она есть, выходим из этого цикла и переходим к блоку изменения значения TradeIsBusy
		{ break; }
		else
		// если GlobalVariableCheck вернула FALSE, значит либо переменной нет, либо при проверке возникла ошибка
		{
			_GetLastError = GetLastError();
			// если это всё таки ошибка, выводим информацию, ждём 0,1 секунды и начинаем проверку сначала
			if ( _GetLastError != 0 )
			{
				Print( "TradeIsBusy() - GlobalVariableCheck ( \"TradeIsBusy\" ) - Error #", _GetLastError );
				Sleep(100);
				continue;
			}
		}

		// если ошибки нет, значит глобальной переменной просто нет, пытаемся создать её
		if ( GlobalVariableSet ( "TradeIsBusy", 1.0 ) > 0 )
		// если GlobalVariableSet > 0, значит глобальная переменная успешно создана. Выходим из ф-ции
		{ return(1); }
		else
		// если GlobalVariableSet вернула значение <= 0, значит при создании переменной возникла ошибка
		{
			_GetLastError = GetLastError();
			// выводим информацию, ждём 0,1 секунды и начинаем попытку сначала
			if ( _GetLastError != 0 )
			{
				Print( "TradeIsBusy() - GlobalVariableSet ( \"TradeIsBusy\", 0.0 ) - Error #", _GetLastError );
				Sleep(100);
				continue;
			}
		}
	}

	//+------------------------------------------------------------------+
	//| Если выполнение функции дошло до этого места, значит глобальная переменная существует.
	//| Ждём, пока TradeIsBusy станет = 0 и меняем значение TradeIsBusy с 0 на 1
	//+------------------------------------------------------------------+
	while( true )
	{
		// если эксперт был остановлен пользователем, прекращаем работу
		if ( IsStopped() ) { Print( "Эксперт был остановлен пользователем!" ); return(-1); }
		// если ожидание длится дольше времени, указанного в переменной MaxWaiting_sec, тоже прекращаем работу
		if ( GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000 ) { Print( "Превышен лимит ожидания (" + MaxWaiting_sec + " сек.)!" ); return(-2); }
		// пытаемся менять значение TradeIsBusy с 0 на 1
		if ( GlobalVariableSetOnCondition( "TradeIsBusy", 1.0, 0.0 ) )
		// если нам это удаётся, выходим из ф-ции, возвращая 1 - "успешное завершение"
		{ return(1); }
		else
		// если нет, возможны 2 причины: TradeIsBusy = 1 (тогда надо ждать), либо возникла ошибка (это мы и проверим)
		{
			_GetLastError = GetLastError();
			// если это всё таки ошибка, выводим информацию и пробуем ещё раз
			if ( _GetLastError != 0 )
			{
				Print( "TradeIsBusy() - GlobalVariableSetOnCondition ( \"TradeIsBusy\", 1.0, 0.0 ) - Error #", _GetLastError );
				continue;
			}
		}

		// если ошибки нет, значит TradeIsBusy = 1 (другой эксперт торгует) - выводим информацию и ждём...
		Comment ( "Ждём, пока другой эксперт закончит торговать..." );
		Sleep(1000);
	}
}

/////////////////////////////////////////////////////////////////////////////////
/**/ void TradeIsNotBusy ()
/////////////////////////////////////////////////////////////////////////////////
// Функция устанавливает значение глобальной переменной TradeIsBusy = 0.
// Если глобальной переменной TradeIsBusy не существует, функция создаёт её.
/////////////////////////////////////////////////////////////////////////////////
{
	// при тестировании нет смысла в разделении торгового потока - просто завершаем работу функции
	if ( IsTesting() ) { return(0); }
	int _GetLastError;

	while( true )
	{
		// если эксперт был остановлен пользователем, прекращаем работу
		if ( IsStopped() ) { Print( "Эксперт был остановлен пользователем!" ); return(-1); }
		// пытаемся установить значение гл. переменной = 0 (или создать гл. переменную)
		if ( GlobalVariableSet( "TradeIsBusy", 0.0 ) > 0 )
		// если GlobalVariableSet вернула значение > 0, значит всё закончилось хорошо. Выходим из ф-ции
		{ return(1); }
		else
		// если GlobalVariableSet вернула значение <= 0, значит возникла ошибка. Выводим информацию, ждём, и пробуем ещё раз
		{
			_GetLastError = GetLastError();
			if ( _GetLastError != 0 )
			{ Print( "TradeIsNotBusy() - GlobalVariableSet ( \"TradeIsBusy\", 0.0 ) - Error #", _GetLastError ); }
		}
		Sleep(100);
	}
}

/*
Шаблон эксперта, использующего функции TradeIsBusy() и TradeIsNotBusy():

#include <TradeContext.mqh>

int start()
{
	// определяем необходимость входа в рынок
	...
	// расчитываем уровни Стоп Лосс, Тейк Профит и размер лота
	...
	// ждём освобождения торгового потока и занимаем его (если произошла ошибка, выходим)
	if ( TradeIsBusy() < 0 ) { return(-1); }
	// обновляем рыночную информацию
	RefreshRates();
	// пересчитываем уровни Стоп Лосс и Тейк Профит
	...
	// открываем позицию
	OrderSend(.....);
	// освобождаем торговый поток
	TradeIsNotBusy();
return(0);
}
*/