Глобальные переменные и «светофор» приправленные Мартингейлом

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

You May Also Like