Создатель сетки 1.1 - страница 4

 
Извините, Кори, у меня есть только один ордер для любой данной позиции сетки, и я протестировал почти все варианты - в течение нескольких недель.

Я иногда удаляю все открытые ордера, чтобы наши друзья из MT4 не расстраивались.

Вы получите эту проблему при бэктестинге, но это не проблема скрипта, а проблема бэктестинга MT4.

Если это продолжится, пожалуйста, дайте мне знать или пришлите мне несколько отчетов, показывающих проблему...

спасибо и благодарность,

hugues
 
Я нашел это. И меня это не забавляет.

Советник создает сетку с заданным мной комментарием "GridEURUSD". Этот комментарий стоит в поле Comment до тех пор, пока ордер находится в ожидании. Если ордер активируется, то комментарий меняется на "activate/auto". В конце концов стало ясно, что такое поведение приводит к описанной проблеме.

Я торгую с Alpari. Они поддерживают MT4 на демо-счетах.

Я проверю, могу ли я обойти это поведение, т.е. использовать магию ордера в качестве идентификатора для сетки, и сообщу вам о результатах.

В процессе тестирования я также внес изменения в скрипт очистки сетки. Я также добавил функциональность для закрытия открытых ордеров. К сожалению, при попытке закрыть открытый ордер я получаю ошибку 129, которая означает, что ордер заблокирован. Но он удаляет все отложенные ордера для данной сетки.

//+------------------------------------------------------------------+ //| RemoveGrid.mq4 | //| Copyright © 2005, hdb | //| http://www.dubois1.net/hdb | //+------------------------------------------------------------------+ #property copyright "Copyright © 2005, hdb" #property link "http://www.dubois1.net/hdb" extern string GridName = "Grid"; extern bool closeOpen = false; //+------------------------------------------------------------------+ //| функция запуска скриптовой программы | //+------------------------------------------------------------------+ int start() { #property show_inputs // показывает параметры - спасибо Slawa... 

//---- int total = OrdersTotal(); int i ; for(i=total-1; i>=0;i--) { OrderSelect(i, SELECT_BY_POS); int type = OrderType(); if ( OrderSymbol()==Symbol() && OrderComment() == GridName ) { bool result = false; switch(type) { case OP_BUY : if ( closeOpen ) { result = OrderClose( OrderTicket(), OrderLots(), Ask, 0, Blue ); } break; case OP_SELL : if ( closeOpen ) { result = OrderClose( OrderTicket(), OrderLots(), Bid, 0, Blue ); } break; //Закрытие отложенных ордеров case OP_BUYLIMIT : result = OrderDelete( OrderTicket() ); break; case OP_BUYSTOP : result = OrderDelete( OrderTicket() ); break; case OP_SELLLIMIT : result = OrderDelete( OrderTicket() ); break; case OP_SELLSTOP : result = OrderDelete( OrderTicket() ); break; } if(result == false) { Print("Order " , OrderTicket() , " failed to close. Error:" , GetLastError() ); // Sleep(3000); }  
        } } //---- return(0); } //+------------------------------------------------------------------+




Кори

 
Хорошо, Кори, спасибо...

Дайте мне знать, если это работает, и я буду использовать магию... так как я не знал, что брокер делает такие странные вещи!!!

спасибо и пожелания,

hugues
 
Вот и все.

Я изменил gridMaker, чтобы использовать OrderMagicNumber вместо комментария. Я также внес небольшие изменения в построение комментария.

Вот результат.

//+------------------------------------------------------------------+ //| MakeGrid.mq4 | //| Copyright © 2005, hdb | //| http://www.dubois1.net/hdb | //+------------------------------------------------------------------+ #property copyright "Copyright © 2005, hdb" #property link "http://www.dubois1.net/hdb" //#property version "1.4beta" // modified by cori. Использование OrderMagicNumber для идентификации сделок сетки extern int uniqueGridMagic = 11111; // Магический номер сделки. должен быть уникальным для идентификации // сделок одной сетки extern double Lots = 0.1; // extern double GridSize = 6; // пипсы между ордерами - размер сетки или ячейки extern double GridSteps = 12; // общее количество ордеров для размещения extern double TakeProfit = 6 ; // количество тиков для фиксации прибыли. обычно это = размер сетки, но вы можете переопределить extern double StopLoss = 0; // если вы хотите добавить стоп-лосс. обычные сетки не используют стоп-лоссы extern double UpdateInterval = 1; // обновление ордеров каждые x минут extern bool wantLongs = true; // нужны ли нам длинные позиции extern bool wantShorts = true; // нужны ли нам короткие позиции extern bool wantBreakout = true;       // хотим ли мы лонги выше цены, шорты ниже цены extern bool wantCounter = true; // хотим ли мы лонги ниже цены, шорты выше цены extern bool limitEMA34 = false; // хотим ли мы лонги только выше ema, шорты только ниже ema // модифицировано cori. только внутренние переменные double LastUpdate = 0; // счетчик используется для записи времени последнего обновления double GridMaxOpen = 0; // максимальное количество открытых позиций string GridName = "Grid"; // идентифицирует сетку. позволяет использовать несколько сосуществующих сеток //+------------------------------------------------------------------+ //| функция инициализации эксперта | //+------------------------------------------------------------------+ int init() { //---- #property show_inputs // показывает параметры - спасибо Slawa....    
 if ( TakeProfit <= 0 ) // { TakeProfit = GridSize; } //---- GridName = StringConcatenate( "Grid", Symbol() ); return(0);
  } //+------------------------------------------------------------------------+ //| проверяет наличие открытой позиции или ордера в области atRate | //| проверяет на лонги, если checkLongs true, иначе проверяет | //| на шорты | //+------------------------------------------------------------------------+ bool IsPosition(double atRate, double inRange, bool checkLongs ) { int totalorders = OrdersTotal(); for(int j=0;j<totalorders;j++) // сканирует все ордера и позиции.... { OrderSelect(j, SELECT_BY_POS); // модифицировано Кори. Использование OrderMagicNumber для идентификации сделок сетки if ( OrderSymbol()==Symbol() && OrderMagicNumber() == uniqueGridMagic )  // ищем только если mygrid и символ... { int type = OrderType(); if (MathAbs( OrderOpenPrice() - atRate ) < inRange) // ищем не точную цену, а близость цены (меньше чем размер сетки) { if ( ( checkLongs && ( type == OP_BUY || type == OP_BUYLIMIT || type == OP_BUYSTOP ) )  || (!checkLongs && ( type == OP_SELL || type == OP_SELLLIMIT || type == OP_SELLSTOP ) ) ) { return(true); } } } } } } 

   return(false); } //+------------------------------------------------------------------+ //| функция запуска скриптовой программы | //+------------------------------------------------------------------+ int start() { //---- int i, j,k, ticket, entermode, totalorders; bool doit; double point, startrate, traderate; //---- if (MathAbs(CurTime()-LastUpdate)> UpdateInterval*60) // мы обновляем при первом вызове и каждые UpdateInterval минут { LastUpdate = CurTime();
   Print("Updating"); point = MarketInfo(Symbol(),MODE_POINT); startrate = ( Ask + point*GridSize/2 ) / point / GridSize; // округляем до числа тиков, кратного GridSize k = startrate ; k = k * GridSize ; startrate = k * point - GridSize*GridSteps/2*point ;          // рассчитываем нижнюю точку входа double EMA34=iMA(NULL,0,34,0,MODE_EMA,PRICE_CLOSE,0); for( i=0;i<GridSteps;i++) { traderate = startrate + i*point*GridSize; if ( wantLongs && (!limitEMA34 || traderate > EMA34)) { if ( IsPosition(traderate,point*GridSize,true) == false )           // проверяем, нет ли у меня открытых ордеров вблизи моей цены: если да, ставим один { double myStopLoss = 0; if ( StopLoss > 0 ) { myStopLoss = traderate-point*StopLoss ; } if ( traderate > Ask ) { entermode = OP_BUYSTOP; } 
              else { entermode = OP_BUYLIMIT ; } 
              
              if ( ((traderate > Ask ) && (wantBreakout)) || ((traderate <= Ask ) && (wantCounter)) ) 

              { // модифицировано Кори. Использование OrderMagicNumber для идентификации сделок сетки ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate+point*TakeProfit,GridName,uniqueGridMagic,0,Green); } } } } if ( wantShorts && (!limitEMA34 || traderate < EMA34)) { if (IsPosition(traderate,point*GridSize,false)== false )           // проверяем, нет ли у меня открытых ордеров вблизи моей цены: если да, ставим один { myStopLoss = 0; if ( StopLoss > 0 ) { myStopLoss = traderate+point*StopLoss ; } if ( traderate > Bid ) { entermode = OP_SELLLIMIT; } 
              else { entermode = OP_SELLSTOP ; } 
              
              if ( ((traderate < Bid ) && (wantBreakout)) || ((traderate >= Bid ) && (wantCounter)) ) 
               { // модифицировано Кори. Использование OrderMagicNumber для идентификации сделок сетки ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate-point*TakeProfit,GridName,uniqueGridMagic,0,Red); } } } } } } return(0); } //+------------------------------------------------------------------+



с уважением, Кори

 
спасибо Кори...

поскольку я уже сделал несколько изменений сам, я интегрировал ваши изменения в новую версию.

Я сделал одно небольшое изменение: чтобы сохранить мои текущие гриды активными, я поставил тест на magic OR gridname...

можете ли вы проверить, правильно ли я это сделал?



//+------------------------------------------------------------------+ //| MakeGrid.mq4 | //| Copyright © 2005, hdb | //| http://www.dubois1.net/hdb | //+------------------------------------------------------------------+ #property copyright "Copyright © 2005, hdb" #property link "http://www.dubois1.net/hdb" //#property version "1.6beta" // modified by cori. Использование OrderMagicNumber для идентификации сделок сетки extern int uniqueGridMagic = 11111; // Магический номер сделки. должен быть уникальным для идентификации // сделок одной сетки extern double Lots = 0.1; // extern double GridSize = 6; // пипсы между ордерами - размер сетки или ячейки extern double GridSteps = 12; // общее количество ордеров для размещения extern double TakeProfit = 12 ; // количество тиков для фиксации прибыли. обычно это = размер сетки, но вы можете переопределить extern double StopLoss = 0; // если вы хотите добавить стоп-лосс. обычные сетки не используют стоп-лоссы extern double UpdateInterval = 1; // обновление ордеров каждые x минут extern bool wantLongs = true; // нужны ли нам длинные позиции extern bool wantShorts = false; // нужны ли нам короткие позиции extern bool wantBreakout = true;     // хотим ли мы лонги выше цены, шорты ниже цены extern bool wantCounter = true; // хотим ли мы лонги ниже цены, шорты выше цены extern bool limitEMA34 = true; // хотим ли мы лонги только выше ema, шорты только ниже ema extern double GridMaxOpen = 0; // максимальное количество открытых позиций : еще не реализовано.. extern bool UseMACD = true; // если true, будет использоваться macd >0 только для лонгов, macd >0 только для шортов // при пересечении отменяются все отложенные ордера. Это отменяет любые // настройки wantLongs и wantShort - по крайней мере, пока. extern bool CloseOpenPositions = false;// если UseMACD, мы также закрываем открытые позиции с убытком? // изменено Кори. только внутренние переменные string GridName = "Grid"; // идентифицирует сетку. позволяет использовать несколько сосуществующих сеток double LastUpdate = 0; // счетчик используется для записи времени последнего обновления //+------------------------------------------------------------------+ //| функция инициализации эксперта | //+------------------------------------------------------------------+ int init() { //---- #property show_inputs // показывает параметры - спасибо Slawa....    
 if ( TakeProfit <= 0 ) // { TakeProfit = GridSize; } //---- // добавлено моей corri и удалено hdb!!! lol... просто чтобы остаться совместимым с открытыми сетками...
// GridName = StringConcatenate("Grid", Symbol() ); return(0); } //+------------------------------------------------------------------------+ //| проверяет наличие открытой позиции или ордера в области atRate | //| проверяет лонги, если checkLongs true, иначе проверяет | //| шорты | //+------------------------------------------------------------------------+ bool IsPosition(double atRate, double inRange, bool checkLongs ) { int totalorders = OrdersTotal();
     for(int j=0;j<totalorders;j++) // сканируем все ордера и позиции.... { OrderSelect(j, SELECT_BY_POS); // модифицировано Кори. Использование OrderMagicNumber для идентификации сделок сетки // добавлено hdb или gridname для совместимости if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName))) )  // ищем только если mygrid и символ... { int type = OrderType(); if (MathAbs( OrderOpenPrice() - atRate ) < inRange) // ищем не точную цену, а ценовую близость (меньше размера сетки) { if ( ( checkLongs && ( type == OP_BUY || type == OP_BUYLIMIT || type == OP_BUYSTOP ) )  || (!checkLongs && ( type == OP_SELL || type == OP_SELLLIMIT || type == OP_SELLSTOP ) ) ) { return(true); } } } } } } 
   return(false); } //+------------------------------------------------------------------------+ //| отменяет все отложенные ордера | //+------------------------------------------------------------------------+ void CloseAllPendingOrders( ) { int totalorders = OrdersTotal(); for(int j=totalorders-1;j>=0;j--) // сканируем все ордера и позиции... { OrderSelect(j, SELECT_BY_POS); // модифицировано согласно Кори. Использование OrderMagicNumber для идентификации сделок сетки // добавляется hdb или gridname для совместимости if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName))) )  // смотрим только если mygrid и symbol...
         { int type = OrderType(); bool result = false; switch(type) { case OP_BUY : result = true ; case OP_SELL : result = true ; //Закрываем отложенные ордера case OP_BUYLIMIT : result = OrderDelete( OrderTicket() ); case OP_BUYSTOP : result = OrderDelete( OrderTicket() ); case OP_SELLLIMIT : result = OrderDelete( OrderTicket() ); case OP_SELLSTOP : result = OrderDelete( OrderTicket() ); } } } } 
   return; } //+------------------------------------------------------------------------+ //| отменяет все отложенные ордера и закрывает открытые позиции | //+------------------------------------------------------------------------+ void CloseOpenOrders() { int total = OrdersTotal(); for(int i=total-1;i>=0;i--) { OrderSelect(i, SELECT_BY_POS); int type = OrderType(); bool result = false; // модифицировано cori. Использование OrderMagicNumber для идентификации сделок сетки // добавляется hdb или gridname для совместимости if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName))) )  // смотрим только если mygrid и символ...
     { // Print("Closing 2 ",type); switch(type) { // Закрываем открытые длинные позиции case OP_BUY : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), 5, Red ); break; // Закрываем открытые короткие позиции case OP_SELL : result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), 5, Red ); break; //Закрываем отложенные ордера case OP_BUYLIMIT : case OP_BUYSTOP :
           case OP_SELLLIMIT : case OP_SELLSTOP : result = OrderDelete( OrderTicket() ); } } if(result == false) { // Alert("Order " , OrderTicket() , " failed to close. Error:" , GetLastError() ); // Sleep(3000); }  
  } return; } //+------------------------------------------------------------------+ //| функция запуска скриптовой программы | //+------------------------------------------------------------------+ int start() { //---- int i, j,k, ticket, entermode, totalorders; bool doit; double point, startrate, traderate; //---- if (MathAbs(CurTime()-LastUpdate)> UpdateInterval*60) // обновляем при первом вызове и каждые UpdateInterval минут { LastUpdate = CurTime();
   point = MarketInfo(Symbol(),MODE_POINT); startrate = ( Ask + point*GridSize/2 ) / point / GridSize; // округляем до числа тиков, кратного GridSize k = startrate ; k = k * GridSize ;
   startrate = k * point - GridSize*GridSteps/2*point ; // вычисляем самую низкую точку входа double EMA34=iMA(NULL,0,34,0,MODE_EMA,PRICE_CLOSE,0); if ( UseMACD ) { double Macd0=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
      double Macd1=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1); double Macd2=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,2); if( Macd0>0 && Macd1>0 && Macd2<0) // крест вверх { CloseAllPendingOrders();
         if ( CloseOpenPositions == true ) { CloseOpenOrders(); } } if( Macd0<0 && Macd1<0 && Macd2>0) // пересечение вниз { CloseAllPendingOrders(); if ( CloseOpenPositions == true ) { CloseOpenOrders(); } } wantLongs = false; wantShorts = false; if( Macd0>0 && Macd1>0 && Macd2>0) // значительно выше нуля { wantLongs = true; } if( Macd0<0 & && Macd1<0 && Macd2<0) // значительно ниже нуля { wantShorts = true; } } } for( i=0;i<GridSteps;i++) { traderate = startrate + i*point*GridSize; if ( wantLongs && (!limitEMA34 || traderate > EMA34)) { if ( IsPosition(traderate,point*GridSize,true) == false )           // проверяем, нет ли у меня открытых ордеров вблизи моей цены: если да, ставим один { double myStopLoss = 0; if ( StopLoss > 0 ) { myStopLoss = traderate-point*StopLoss ; } if ( traderate > Ask ) { entermode = OP_BUYSTOP; } 
              else { entermode = OP_BUYLIMIT ; } 
              if ( ((traderate > Ask ) && (wantBreakout)) || ((traderate <= Ask ) && (wantCounter)) ) 
              { // модифицировано Кори. Использование OrderMagicNumber для идентификации сделок сетки ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate+point*TakeProfit,GridName,uniqueGridMagic,0,Green); } } } } if ( wantShorts && (!limitEMA34 || traderate < EMA34)) { if (IsPosition(traderate,point*GridSize,false)== false )           // проверяем, нет ли у меня открытых ордеров вблизи моей цены: если да, ставим один { myStopLoss = 0; if ( StopLoss > 0 ) { myStopLoss = traderate+point*StopLoss ; } if ( traderate > Bid ) { entermode = OP_SELLLIMIT; } 
              else { entermode = OP_SELLSTOP ; } 
              
              if ( ((traderate < Bid ) && (wantBreakout)) || ((traderate >= Bid ) && (wantCounter)) ) 
                { // модифицировано Кори. Использование OrderMagicNumber для идентификации сделок сетки ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate-point*TakeProfit,GridName,uniqueGridMagic,0,Red); } } } } } } return(0); } //+------------------------------------------------------------------+
 
Привет hdb,

кажется нормальным. Но вы должны определить GridName как extern, что я изменил, потому что мне не нужен был этот параметр.

приветствую, Кори.
 
ВНИМАНИЕ всем пользователям GridMaker - в функции IsPosition есть ошибка - в результате не все слоты сетки заполняются.

Вы можете изменить строку :

if (MathAbs( OrderOpenPrice() - atRate ) < inRange) // dont look for exact price but price proximity (less than gridsize)

to

if (MathAbs( OrderOpenPrice() - atRate ) < (inRange*0.9)) // не ищем точную цену, а ищем близость цены (меньше размера сетки) - добавлено 0.9 из-за ошибок плавающего понтона


и это исправляет проблему.

Извините за любые неудобства...

hugues
 
Привет, Хугес,

Эта проблема уже существует?

Нашел нечто подобное в старом MQL2.

Действительно верный способ обойти эту проблему - сделать что-то вроде:

int intOOP = MathRound( OrdeOpenPrice() / Point );

для всех ваших двойных переменных. Тогда у вас будут все прямые переменные int, которые сравнимы без ошибок.

Придется написать немного больше, чтобы все было ясно и понятно, но зато будет меньше ошибок.

С уважением,

Кори
 
Вы правы, Кори, это гораздо элегантнее! Просто я ленивая!

с уважением,
hugues
 
Представляем вашему вниманию обновление советника GridMaker. В этой версии я:

1) изменил логику для UseMACD, wantLongs, wantShorts. Раньше, если useMACD был установлен, советник брал лонги и шорты, независимо от флагов wnatLongs и wantShorts. Теперь useMACD не отменяет эти флаги, поэтому советник может быть только длинным с useMACD или только коротким.

2) Я добавил дополнительную проверку, чтобы убедиться, что не было открытых ордеров не по ту сторону EMA, если был установлен limitEMA34. Раньше ордера размещались выше или ниже EMA, но через несколько часов EMA перемещалась... поэтому ордера были по обе стороны EMA.

3) Похоже, есть ошибка в операторе switch в OrderType(). Я не уверен, что это такое, но он действительно ведет себя забавно. Я просто удалил оператор switch и заменил его на "if"... мне это не нравится, но это работает!

4) Я сделал период EMA переменной... удобно для бэктестинга...

У меня также есть несколько скриптов-компаньонов, если кто-то хочет:

1) для удаления незаполненных открытых ордеров для пары
2) для удаления всех открытых ордеров для всех пар одним махом
3) для закрытия всех позиций и удаления открытых ордеров.
4) получить простую статистику о поведении сетки по открытым позициям и истории.

Вот код V1.08:


//+------------------------------------------------------------------+ //| MakeGrid.mq4 | //| Copyright © 2005, hdb | //|
http://www.dubois1.net/hdb | //+------------------------------------------------------------------+ #property copyright "Copyright © 2005, hdb" #property link "http://www.dubois1.net/hdb" //#property version "1.8" // DISCLAIMER ***** IMPORTANT NOTE ***** READ BEFORE USING ***** // Этот советник может открывать и закрывать реальные позиции и, следовательно, совершать реальные сделки и терять реальные деньги.
// Это не "торговая система", а простой робот, который размещает сделки по фиксированным правилам. // Автор не претендует на прибыльность этой системы и не предлагает использовать // этот советник иначе как для тестирования на демо-счетах. // Использование этой системы бесплатно - но вы не можете перепродавать ее - и не имеет никаких гарантий относительно ее // пригодности для любых целей.
// Используя эту программу, вы косвенно подтверждаете, что понимаете, что она делает, и соглашаетесь с тем, что // автор не несет никакой ответственности за любые потери. // Перед использованием, пожалуйста, также проверьте у своего брокера, что его системы адаптированы для наиболее частых сделок, // связанных с этим экспертом. // В 1.8 изменения // превратили wantLongs и wantShorts в локальные переменные. Раньше, если вы устанавливали UseMACD в true, // он делал лонги и шорты и просто игнорировал флаги wantLongs и wantShorts. 
// Теперь эти флаги не игнорируются. // Добавлен цикл для проверки наличия "незаконных" открытых ордеров выше или ниже EMA при использовании флага limitEMA34 //. Они накапливаются со временем и никогда не удаляются, что связано с движением EMA. // удалены инструкции switch, так как они не работают - заменены на операторы if // сделана переменная периода EMA // // // модифицирована Кори. Использование OrderMagicNumber для идентификации сделок сетки extern int uniqueGridMagic = 11111; // Магический номер сделки. должен быть уникальным для идентификации // сделок одной сетки extern double Lots = 0.1; // extern double GridSize = 6; // пипсы между ордерами - размер сетки или ячейки extern double GridSteps = 12; // общее количество ордеров для размещения extern double TakeProfit = 12 ; // количество тиков для фиксации прибыли. обычно это = размер сетки, но вы можете переопределить extern double StopLoss = 0; // если вы хотите добавить стоп-лосс. обычные сетки не используют стоп-лоссы extern double UpdateInterval = 1; // обновление ордеров каждые x минут extern bool wantLongs = true; // нужны ли нам длинные позиции extern bool wantShorts = true; // нужны ли нам короткие позиции extern bool wantBreakout = true;     // хотим ли мы лонги выше цены, шорты ниже цены extern bool wantCounter = true; // хотим ли мы лонги ниже цены, шорты выше цены extern bool limitEMA = true; // хотим ли мы лонги только выше ema, шорты только ниже ema extern int EMAperiod = 34; // длина EMA.. ранее была зафиксирована на 34 extern double GridMaxOpen = 0; // максимальное количество открытых позиций: пока не реализовано... extern bool UseMACD = true; // если true, будет использоваться macd >0 только для лонгов, macd >0 только для шортов // при пересечении отменяются все отложенные ордера. Это отменяет любые // настройки wantLongs и wantShort - по крайней мере, сейчас. extern bool CloseOpenPositions = false;// если UseMACD, мы также закрываем открытые позиции с убытком? extern bool doHouseKeeping = true; // просто тест // модифицированный Кори. только внутренние переменные string GridName = "Grid"; // идентифицирует сетку. позволяет использовать несколько сосуществующих сеток double LastUpdate = 0; // счетчик используется для записи времени последнего обновления //+------------------------------------------------------------------+ //| экспертная функция инициализации | //+------------------------------------------------------------------+ int init() { //---- #property show_inputs // показывает параметры - спасибо Славе...    
//---- // добавлено моим corri и удалено hdb!!! lol... просто чтобы остаться совместимым с открытыми сетками...
// GridName = StringConcatenate("Grid", Symbol() ); return(0); } //+------------------------------------------------------------------------+ //| проверяет наличие открытой позиции или ордера в области atRate | //| проверяет лонги, если checkLongs true, иначе проверяет | //| шорты | //+------------------------------------------------------------------------+ bool IsPosition(double atRate, double inRange, bool checkLongs ) { int totalorders = OrdersTotal();
     for(int j=0;j<totalorders;j++) // сканируем все ордера и позиции.... { OrderSelect(j, SELECT_BY_POS); // модифицировано Кори. Использование OrderMagicNumber для идентификации сделок сетки // добавлено hdb или gridname для совместимости if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName))) )  // ищем только если mygrid и символ... { int type = OrderType(); if (MathAbs( OrderOpenPrice() - atRate ) < (inRange*0.9)) // ищем не точную цену, а ценовую близость (меньше размера сетки) - добавлено 0.9 из-за ошибок с плавающей запятой { if ( ( checkLongs && ( type == OP_BUY || type == OP_BUYLIMIT || type == OP_BUYSTOP ) )  || (!checkLongs && ( type == OP_SELL || type == OP_SELLIMIT || type == OP_SELLSTOP ) ) ) { return(true); } } } } } } 
   return(false); } //+------------------------------------------------------------------------+ //| отменяет все отложенные ордера | //+------------------------------------------------------------------------+ void CloseAllPendingOrders( ) { int totalorders = OrdersTotal(); for(int j=totalorders-1;j>=0;j--) // сканируем все ордера и позиции... { OrderSelect(j, SELECT_BY_POS); // модифицировано согласно Кори. Использование OrderMagicNumber для идентификации сделок сетки // добавляется hdb или gridname для совместимости if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName))) )  // смотрим только если mygrid и символ... { int type = OrderType(); if ( type > 1 ) bool result = OrderDelete( OrderTicket() ); } } 
   return; } //+------------------------------------------------------------------------+ //| отменяет все отложенные ордера и закрывает открытые позиции | //+------------------------------------------------------------------------+ void CloseOpenOrders() { int total = OrdersTotal(); for(int i=total-1;i>=0;i--) { OrderSelect(i, SELECT_BY_POS); int type = OrderType(); bool result = false; // модифицировано cori. Использование OrderMagicNumber для идентификации сделок сетки // добавляется hdb или gridname для совместимости if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName))) )  // смотрим только если mygrid и символ...
     { //Закрываем открытые длинные позиции if ( type == OP_BUY ) result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), 5, Red );
           //Закрываем открытые короткие позиции if ( type == OP_SELL ) result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), 5, Red ); //Закрываем отложенные ордера if ( type > 1 ) result = OrderDelete( OrderTicket() ); } } return;
} //+------------------------------------------------------------------------+ //| отменяет все открытые ордера, которые попадают не на ту сторону EMA | //+------------------------------------------------------------------------+ void CloseOrdersfromEMA( double theEMAValue ) { int totalorders = OrdersTotal(); for(int j=totalorders-1;j>=0;j--) // сканируем все ордера и позиции.... { OrderSelect(j, SELECT_BY_POS); if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName))) )  // смотрим только если mygrid и symbol...
         { int type = OrderType(); bool result = false; //если (type > 1) Print(type," ",theEMAValue," ",OrderOpenPrice()); if ( type == OP_BUYLIMIT && OrderOpenPrice() <= theEMAValue ) result = OrderDelete( OrderTicket() ); if ( type == OP_BUYSTOP &&. OrderOpenPrice() <= theEMAValue ) result = OrderDelete( OrderTicket() ); if ( type == OP_SELLLIMIT && OrderOpenPrice() >= theEMAValue ) result = OrderDelete( OrderTicket() ); if ( type == OP_SELLSTOP && OrderOpenPrice() >= theEMAValue ) result = OrderDelete( OrderTicket() ); } } 
   return; } //+------------------------------------------------------------------+ //| функция запуска скриптовой программы | //+------------------------------------------------------------------+ int start() { //---- int i, j,k, ticket, entermode, totalorders; bool doit; double point, startrate, traderate; //---- параметры установки if ( TakeProfit <= 0 ) // { TakeProfit = GridSize; } bool myWantLongs = wantLongs;
 bool myWantShorts = wantShorts; //---- if (MathAbs(CurTime()-LastUpdate)> UpdateInterval*60) // мы обновляем при первом вызове и каждые UpdateInterval минут { LastUpdate = CurTime();
   point = MarketInfo(Symbol(),MODE_POINT); startrate = ( Ask + point*GridSize/2 ) / point / GridSize; // округляем до числа тиков, кратного GridSize k = startrate ; k = k * GridSize ; startrate = k * point - GridSize*GridSteps/2*point ;          // рассчитываем самую низкую точку входа double myEMA=iMA(NULL,0,EMAperiod,0,MODE_EMA,PRICE_CLOSE,0); if (limitEMA) { if (doHouseKeeping) CloseOrdersfromEMA(myEMA); } if ( UseMACD ) { double Macd0=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
      double Macd1=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1); double Macd2=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,2); if( Macd0>0 && Macd1>0 && Macd2<0) // пересечение вверх { CloseAllPendingOrders(); if ( CloseOpenPositions == true ) { CloseOpenOrders(); } } if( Macd0<0 && Macd1<0 && Macd2>0) // пересечение вниз { CloseAllPendingOrders();
         if ( CloseOpenPositions == true ) { CloseOpenOrders(); } } } myWantLongs = false; myWantShorts = false; if( Macd0>0 && Macd1>0 && Macd2>0 && wantLongs )     // значительно выше нуля { myWantLongs = true; } if( Macd0<0 && Macd1<0 && Macd2<0 && wantShorts )     // значительно ниже нуля { myWantShorts = true; } } for( i=0;i<GridSteps;i++) { traderate = startrate + i*point*GridSize; if ( myWantLongs && (!limitEMA || traderate > myEMA)) { if ( IsPosition(traderate,point*GridSize,true) == false )           // проверяем, нет ли у меня открытых ордеров вблизи моей цены: если да, ставим один { double myStopLoss = 0; if ( StopLoss > 0 ) { myStopLoss = traderate-point*StopLoss ; } if ( traderate > Ask ) { entermode = OP_BUYSTOP; } 
              else { entermode = OP_BUYLIMIT ; } 
              if ( ((traderate > Ask ) && (wantBreakout)) || ((traderate <= Ask ) && (wantCounter)) ) 
              { // модифицировано Кори. Использование OrderMagicNumber для идентификации сделок сетки ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate+point*TakeProfit,GridName,uniqueGridMagic,0,Green); } } } } if ( myWantShorts && (!limitEMA || traderate < myEMA)) { if (IsPosition(traderate,point*GridSize,false)== false )           // проверяем, нет ли у меня открытых ордеров вблизи моей цены: если да, ставим один { myStopLoss = 0; if ( StopLoss > 0 ) { myStopLoss = traderate+point*StopLoss ; } if ( traderate > Bid ) { entermode = OP_SELLLIMIT; } 
              else { entermode = OP_SELLSTOP ; } 
              
              if ( ((traderate < Bid ) && (wantBreakout)) || ((traderate >= Bid ) && (wantCounter)) ) 
                { // модифицировано Кори. Использование OrderMagicNumber для идентификации сделок сетки ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate-point*TakeProfit,GridName,uniqueGridMagic,0,Red); } } } } } } return(0); } //+------------------------------------------------------------------+
Причина обращения: