Мы уже использовали в предыдущих уроках глобальные переменные, видимые в любом месте программы. Есть еще один вид глобальных переменных (GlobalVariables). Это переменная клиентского терминала, ее значения доступны всем программам клиентского терминала (скрипт, индикатор, советник). С ее помощью, например можно организовать связь между двумя советниками или между советником и индикатором. GV-переменная записывается на жесткий диск, так что в ней сохраняются данные, даже если компьютер выключен. Если к GV-переменной не обращались в течении 30 дней она автоматически удаляется с жесткого диска.
С GV-переменной одновременно может работать только одна программа. Если к GV-переменной одновременно обратятся несколько советников, данные скорей всего будут испорчены.
Несколько функций для работы с GV-переменными.
GlobalVariableCheck(string имя_GV-переменной) – Проверяет существует ли данная переменная. Если да возвращает true иначе false.
GlobalVariableGet(string имя_GV-переменной) – Возвращает значение существующей глобальной переменной (тип double), или 0 в случае ошибки.
GlobalVariableSet(string имя_GV-переменной,double числовое_значение) – Если переменой нет, создает. Если есть, присваивает ей новое значение.
GlobalVariableSetOnCondition(stringимя_GV-переменной,double новое_числовое_значение,double проверочное_числовое_значение) – Устанавливает новое значение существующей глобальной переменной и вернет true, если переменная существует и текущее значение равно проверочному значению. В других случаях вернет false.
В этом уроке рассмотрим пример применения GV-переменной. Создадим GV-переменную «Semafor», она будет иметь значение -1 или 1, «зеленый» и «красный свет» соответственно.
Задача организовать «светофор», что бы при работе нескольких экспертов они не мешали один одному и торговали по очереди. Для этого напишем две функции Lock() и UnLock(),Lock() будет вызываться перед OrderSend а UnLock() после.
// проверяем, есть ли от других экспертов нам "зеленый свет" для торговли... если есть пытаемся заблокировать торговлю для других if(Lock() == -1) return(0); // если не удалось заблокировать... выходим // заблокировали... теперь можно выставить ордер OrderSend(Symbol(),cmd,lot,price,3,stoploss,takeprofit,NULL,Magic№,0,Green); UnLock(); // разблокируем... разрешаем торговлю для других
Перед торговой операцией советник проверяет, есть ли «зеленый свет» (не торгует ли другой советник в данный момент). Вызываем функции Lock() она проверяет, есть ли «зеленый» для торговли, если да устанавливает «красный» для других советников (блокирует их). Выполняет все необходимые торговые операции и вызывает функцию UnLock() которая переключает «светофор» на «зеленый», разрешает другим экспертам совершать торговые операции.
Функции Lock() и UnLock() почти идентичны, в UnLock() GlobalVariableSetOnCondition помещена в бесконечный цикл.
while(!IsStopped()) // если эксперт остановлен - выходим из цикла
{ // бесконечный цикл
if(GlobalVariableSetOnCondition("Semafor", -1.0, 1.0)) return(-1);// зажгли "зеленый". разблокировали всех
Sleep(100); // если не удалось разблокировать. ждем 0.1 сек. и пробуем снова
}
Если не удалось зажечь «зеленый» сразу, то в бесконечном цикле будем пробовать снова и снова, пока не зажжется «зеленый» или будет нажата кнопка остановки «эксперта» (IsStopped).
IsStopped() – Возвращается TRUE, если программа (эксперт или скрипт) получила команду на завершение своей работы, иначе возвращает FALSE.
Теперь о самом «эксперте». Все это сделаем для примера в «советнике» торгующем по системе Мартингейла.
Алгоритм «советника»:
Если нет открытых ордеров «эксперт» смотрит историю закрытых ордеров. И остатний из них закрылся с профитом значит, предыдущий цикл завершился успешно, начинаем новый открываем buy ордер с выставленными стоплосом и тейкпрофитом. Если же предыдущий ордер закрылся по стоплосу значит, цикл не закончился «советник» открывает ордер в противоположную сторону с удвоенным лотом. Если цена пошла в нужную сторону и ордер закрылся по тейкпрофиту, цикл завершен и сразу открывается новый buy ордер (начало нового цикла).
При переключении в настройках «советника» Trade в FALSE и если есть открытый ордер, «эксперт» не перестанет выставлять ордера, пока один из них не закроется с прибылью (завершится цикл). И новый цикл не начнется.
Функция HistoryOrders() в отличии от Orders() из предыдущих уроков ведет среди закрытых ордеров, благодаря идентификатору MODE_HISTORY в функции OrderSelect.
OrdersHistoryTotal() – Возвращает количество закрытых и удаленных ордеров в истории текущего счета, загруженной в клиентском терминале. Размер списка истории зависит от текущих настроек вкладки «История счета» терминала.
Полный код программы:
//+------------------------------------------------------------------+
//| Martin.mq4 |
//| Copyright © 2011, MetaQuotes Software Corp. |
//| |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2011, MetaQuotes Software Corp."
#property link "http://www.metaquotes.net"
//--- input parameters
extern int Magic№ = 777;
extern bool Trade = false; //запрещаем/разрешаем торговлю
extern int TakeProfit = 50;
extern int StopLoss = 50;
int LastOrder; // позиция в массиве останего из закрытых ордеров
double HMas_Ord_New[1000][7]; // массив закрытых ордеров
double HMas_Ord_Old[1000][7];
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
double Lot, LastLot, profit;
if(OrdersTotal() == 0) // если нет открытых ордеров.. будем открывать
{
HistoryOrders(); // заполняем масив закрытых ордеров
profit = HMas_Ord_New[LastOrder][6]; // получаем профит останего ордера
if(Trade == true && ((profit > 0) || (profit == 0))) // если прошлый ордер закрылся с прибылью...
{ // начинаем новый цикл
Send(OP_BUY,0.01,Ask,Ask - StopLoss*Point); // открываем бай
return(0);
}
if((profit > 0) || (profit == 0)) return(0);
// если дошли сюда значит прошлый ордер закрылся с убытком
LastLot = HMas_Ord_New[LastOrder][4]; // получаем размер лота останего из закрытых ордеров
// определяем какое это колено Мартина :)
if(LastLot == 0.01) Lot = 0.02; // если лот убыточного ордера был 0.01.. лот нового будет 0.02
if(LastLot == 0.02) Lot = 0.04; // если лот убыточного ордера был 0.02.. лот нового будет 0.04
if(LastLot == 0.04) Lot = 0.08;
if(LastLot == 0.08) Lot = 0.16;
if(LastLot == 0.16) Lot = 0.32;
if(LastLot == 0.32) Lot = 0.64;
if(LastLot == 0.64) Lot = 1.28;
if(LastLot == 1.28) Lot = 2.56;
if(LastLot == 2.56) Lot = 5.12;
if(HMas_Ord_New[LastOrder][3] == 0) Send(OP_SELL,Lot,Bid,HMas_Ord_New[LastOrder][5]); // если прошлый ордер был бай.. открываем селл
if(HMas_Ord_New[LastOrder][3] == 1) Send(OP_BUY,Lot,Ask,HMas_Ord_New[LastOrder][5]); // если прошлый ордер был селл.. открываем бай
}
return(0);
}
//-------------------------------------------------------------------+
// Функция открытия ордеров |
//-------------------------------------------------------------------+
int Send(int cmd, double lot, double price, double stoploss)
{
double takeprofit;
if(cmd == OP_BUY) takeprofit = price + TakeProfit*Point;
if(cmd == OP_SELL) takeprofit = price - TakeProfit*Point;
// проверяем, есть ли от других экспертов нам "зеленый свет" для торговли... если есть пытаемся заблокировать торговлю для других
if(Lock() == -1) return(0); // если не удалось заблокировать... выходим
// заблокировали... теперь можно выставить ордер
OrderSend(Symbol(),cmd,lot,price,3,stoploss,takeprofit,NULL,Magic№,0,Green);
UnLock(); // разблокируем... разрешаем торговлю для других
}
//-------------------------------------------------------------------+
//учет закрытых ордеров... сколько, каких, цена открытия и тд. |
//-------------------------------------------------------------------+
int HistoryOrders()
{
int ticket;
int Qnt = 0; // Счётчик количества ордеров // Обнуление счётчика ордеров
LastOrder = 0;
ArrayCopy(HMas_Ord_Old, HMas_Ord_New); // Сохраняем предыдущую историю
ArrayInitialize(HMas_Ord_New,0); // Обнуление массива
for(int i = 0; i < OrdersHistoryTotal(); i++) { Qnt++; if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY) == false) continue;//Если есть следующ. if(Magic№ != OrderMagicNumber()) continue; if(Symbol() != OrderSymbol()) continue; //.. и наша вал.пара HMas_Ord_New[Qnt][1] = OrderMagicNumber(); // Магическое число HMas_Ord_New[Qnt][2] = OrderTicket(); // Номер ордера HMas_Ord_New[Qnt][3] = OrderType(); // Тип ордера HMas_Ord_New[Qnt][4] = OrderLots(); // Количество лотов HMas_Ord_New[Qnt][5] = OrderOpenPrice(); // Курс открытия орд HMas_Ord_New[Qnt][6] = OrderProfit(); if(OrderTicket() > ticket)
{ // ищем останий между закрытыми
ticket = OrderTicket();
LastOrder = Qnt; // запоминаем позицию в масиве останего ордера
}
}
HMas_Ord_New[0][0] = Qnt; // Колич. ордеров
return(0);
}
//+------------------------------------------------------------------+
//| Функция блокировки торговли для других экспертов |
//+------------------------------------------------------------------+
int Lock()
{
bool CheckGV = false;
CheckGV = GlobalVariableCheck("Semafor");// контроль переменной перед использованием
if(CheckGV == false) // проверим, существует ли переменная Semafor
{ // переменная не существует,
if(GetLastError() != 0) return(-1);
// ошибки нет
if(GlobalVariableSet("Semafor", -1.0) == 0) return(-1);// создадим переменную
// переменная создана
}
if(GlobalVariableGet("Semafor") == -1.0)
{ // "зеленый свет" загорелся, зажигаем "красный свет"
if(GlobalVariableSetOnCondition("Semafor", 1.0, -1.0)) return(1);// зажгли "красный". других заблокировали
// нас опередили, поэтому ждем "зеленого света"
Sleep(100);
}
return(-1);
}
//+------------------------------------------------------------------+
//| Функция разблокировки торговли для других экспертов |
//+------------------------------------------------------------------+
int UnLock()
{
bool CheckGV = false;
CheckGV = GlobalVariableCheck("Semafor"); // контроль переменной перед использованием
if(CheckGV == false) // проверим, существует ли переменная Semafor
{ // переменная не существует
if(GetLastError() != 0) return(-1);
if(GlobalVariableSet("Semafor", -1.0) == 0) return(-1); // создадим переменную
// переменная создана, поэтому выходим return(-1);
}
while(!IsStopped()) // если эксперт остановлен - выходим из цикла
{ // бесконечный цикл
if(GlobalVariableSetOnCondition("Semafor", -1.0, 1.0)) return(-1); // зажгли "зеленый". разблокировали всех
Sleep(100); // если неудалось разблокировать. ждем 0.1 сек. и пробуем снова
}
}
Внимание. Этот «эксперт» в отличие от тех, что мы изучали ранее, полуфабрикат его можно использовать только в тестере. Все что мы учили в прошлых уроках о «правильной» торговле (обработка ошибок и тд.) здесь отсутствуют. Довести его до ума это Ваше домашнее задание.
Исходник: Martin
Трейлинг — https://forexlab.ru/mql-trailing/








