Мы уже использовали в предыдущих уроках глобальные переменные, видимые в любом месте программы. Есть еще один вид глобальных переменных (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/