Запрет торговли в одном баре. - страница 6

 
rosych #:

Посмотрел тут варианты ответа на твой вопрос,но мне кажется доходнее и наджнее примерно так:

//+------------------------------------------------------------------+

bool ProverkaTimeBuy(){
for(int bz=OrdersTotal()-1;bz>=0;bz--){
if(OrderSelect(bz,SELECT_BY_POS,MODE_TRADES)){
if(OrderSymbol()==Symbol()){
if(OrderType()==OP_BUY &&
OrderMagicNumber()==1 &&
OrderOpenTime()>=Time[0]){return(false);}
else{return(true);}
}
}
}
return(true);
}
bool ProverkaTimeSell(){
for(int sz=OrdersTotal()-1;sz>=0;sz--){
if(OrderSelect(sz,SELECT_BY_POS,MODE_TRADES)){
if(OrderSymbol()==Symbol()){
if(OrderType()==OP_SELL &&
OrderMagicNumber()==2 &&
OrderOpenTime()>=Time[0]){return(false);}
else{return(true);}
}
}
}
return(true);
}
//+------------------------------------------------------------------+

кстати, из продвинутых кто что посоветует мне. обмен опытом приветствуется. ))))))))

В этом коде выражение  else{return(true); дважды лишнее.


bool ProverkaTimeBuy()

{

      for(int b=OrdersTotal()-1;b>=0;b--)

         if(OrderSelect(b,SELECT_BY_POS,MODE_TRADES))

            if(OrderSymbol()==Symbol())

               if(OrderType()==OP_BUY && OrderMagicNumber()==1 && OrderOpenTime()>=Time[0])

                  return(false);

   return(true);

}

//************************************************************************************************/

bool ProverkaTimeSell()

{

      for(int s=OrdersTotal()-1;s>=0;s--)

         if(OrderSelect(s,SELECT_BY_POS,MODE_TRADES))

            if(OrderSymbol()==Symbol())

               if(OrderType()==OP_SELL && OrderMagicNumber()==2 && OrderOpenTime()>=Time[0])

                  return(false);

   return(true);

}



И вообще не рационально, в том числе и у Кима использовать циклы.

Рациональнее запоминать время бара при открытии ордера. Время бара будет всегда последнее пока не появится следующий. Время следующего больше. Вот и проверяйте.

 
Igor Kim #:
Пример использования:

Почему oot не проиндексировали нулем? Кок вы неизвестное значение сравниваете с временем открытия ордера?

 
Alexey Klenov #:

Использование

открытие бай

Открытие селл

if (timeoldopen!=Time[0])

А чему равен timealdopen, что вы его с чем-то сравниваете? Перед каждым циклом его надо индексировать нулем.

 
TheXpert #:

Если речь идет о контроле баров в целом:


Для тестера подойдет такой вариант:

Я пользуюсь таким:


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

Аесли стопы не успели выставиться или трал какой-то? А вы будете ждать нового ордера. Он откроется, а вы снова курите.

 

Довольно интересную тему поднял топикстартер. Я тоже пробовал разные варианты. За годы программирования уже сложился такой подход: Предположим у нас есть некий сигнал и по нему должен открыться один и только один ордер в нужную сторону. Я для осуществления этого сделал себе функцию "Счётчик ордеров". Скажем так, по лонговому сигналу должен открыться лонговый ордер. Делаем проверку: если счётчик лонговых ордеров = нулю, то открыть ордер. Пусть на данном тике ордер открылся. На следующем тике советник обнаружит снова лонговый сигнал, но счётчик скажет, что у нас уже есть рыночный лонг. Поэтому до тех пор, пока рыночный жив, ни по какому лонговому сигналу Бай-ордер больше не откроется.

Бывает, что время жизни ордера меньше времени жизни свечи (свечка ещё не закрылась, а ордер уже отработал). Ордер открылся, отработал, цена уехала. Ордера уже нет, а свечка ещё не закрылась и советник видит, что сигнал есть. В случае, если нам уже не выгодно открываться по такой цене (нужно было открываться на первых тиках), то встраиваю дополнительную проверку. Для этого я сделал себе функцию, возвращающую время закрытия последнего рыночного ордера. Итак, что имеем, если есть сигнал и нет ордера и при этом время закрытия последнего рыночного меньше времени открытия свечи (менее, чем Time[0]), то открываем позу.

 
Vitaly Murlenko #:

Довольно интересную тему поднял топикстартер. Я тоже пробовал разные варианты. За годы программирования уже сложился такой подход: Предположим у нас есть некий сигнал и по нему должен открыться один и только один ордер в нужную сторону. Я для осуществления этого сделал себе функцию "Счётчик ордеров". Скажем так, по лонговому сигналу должен открыться лонговый ордер. Делаем проверку: если счётчик лонговых ордеров = нулю, то открыть ордер. Пусть на данном тике ордер открылся. На следующем тике советник обнаружит снова лонговый сигнал, но счётчик скажет, что у нас уже есть рыночный лонг. Поэтому до тех пор, пока рыночный жив, ни по какому лонговому сигналу Бай-ордер больше не откроется.

Бывает, что время жизни ордера меньше времени жизни свечи (свечка ещё не закрылась, а ордер уже отработал). Ордер открылся, отработал, цена уехала. Ордера уже нет, а свечка ещё не закрылась и советник видит, что сигнал есть. В случае, если нам уже не выгодно открываться по такой цене (нужно было открываться на первых тиках), то встраиваю дополнительную проверку. Для этого я сделал себе функцию, возвращающую время закрытия последнего рыночного ордера. Итак, что имеем, если есть сигнал и нет ордера и при этом время закрытия последнего рыночного меньше времени открытия свечи (менее, чем Time[0]), то открываем позу.

То есть, по сути можно перебирать ордера и рыночные и в истории сразу тоже. И сравнивать их с временем нужной свечи. Если на баре с нужным временем есть или были уже ордера (в рамках данного времени) - то на этом баре больше ордера не открывать. Так что ли???

 
to_ha #:

То есть, по сути можно перебирать ордера и рыночные и в истории сразу тоже. И сравнивать их с временем нужной свечи. Если на баре с нужным временем есть или были уже ордера (в рамках данного времени) - то на этом баре больше ордера не открывать. Так что ли???

Смотрите, пишем функцию:

//=========== SchBuy()  ===============================
//  Функция возвращает количество Buy-ордеров
//   SchBuy      - счётчик Buy ордеров
//-----------------------------------------------------------
int SchBuy(int MAGIC){
  string SMB=Symbol();
  int SchBuy=0;
  for(int i=OrdersTotal()-1;i>=0;i--){
    if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){SelectError(i);}
    else{
      if(OrderSymbol()!= SMB || OrderMagicNumber()!= MAGIC){continue;}
      if(OrderType()==OP_BUY){ 
        SchBuy++;
      }  
    }
  }
  return(SchBuy);
}  

В теле советника пишем:

string Signal="";
// тут делаем какие-то поверки, при которых эта переменная принимает какое-то значение, например так:
Signal="BUY";
// далее делаем проверку и открытие ордера
if(SchBuy(MAGIC)+SchSell(MAGIC)<=0){// Рыночных нет
  if(Signal=="BUY"){
    // тут подготавливаем переменные цены, тейка, стоп-лосса...
    int TicketBuy=OrderSend(SMB,OP_BUY,LOT,PR,PRSK,SL,TP,NULL,MAGIC,0,CLR_NONE);
    if(TicketBuy<0){
      Print("Ошибка произошла в блоке установки стартовых ордеров");
      Print("PR = ",PR," SL= ",0," TP = ",TP);
      Print("Ошибка № ",GetLastError()," при установке Buy-ордера");
    }
  }
}

после блока 

if(Signal=="BUY"){

вставляем такой же для Sell-ордеров

 

По поводу времени. Можно точно так же получить время закрытия последнего ордера. Для этого нужно сперва получить его тикет из истории ордеров. Далее, зная тикет, мы можем выбрать этот ордер по тикету и запросить о нём любую информацию. Например, если мы разделяем открытие лонгов и шортов, мы можем запросить через тикет какого типа этот ордер, в покупку он был, или в продажу. Если например, он был в покупку и у нас сигнал в покупку, то опять выбираем его через тикет и запрашиваем время его закрытия. Смотрите:

// ======================= TypeOrderHistory(string SMB,int MAGIC) ========================
//функция возвращает тип последнего закрытого ордера истории
// OP_BUY        0   Покупка 
// OP_SELL       1   Продажа 
// OP_BUYLIMIT   2   Отложенный ордер BUY LIMIT 
// OP_SELLLIMIT  3   Отложенный ордер SELL LIMIT 
// OP_BUYSTOP    4   Отложенный ордер BUY STOP 
// OP_SELLSTOP   5   Отложенный ордер SELL STOP 
// -----------------------------------------------------
int TypeOrderHistory(string SMB,int MAGIC){
        datetime TimeOpenOrder=0;
        int Type=(-1);
        for(int i=OrdersHistoryTotal()-1;i>=0;i--){
                if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)){
                        Print("Ошибка ", GetLastError(), " при выборе ордера номер ",i," по паре ",SMB);
                }
                else{
                        if(OrderSymbol()!=SMB || OrderMagicNumber()!=MAGIC){continue;}
                        if(OrderType()==OP_BUY){
                                if(OrderOpenTime()>TimeOpenOrder){
                                        TimeOpenOrder=OrderOpenTime();
                                        Type=OrderType();
                                }
                        }
                        if(OrderType()==OP_SELL){
                                if(OrderOpenTime()>TimeOpenOrder){
                                        TimeOpenOrder=OrderOpenTime();
                                        Type=OrderType();
                                }
                        }
                }
        }    
        return(Type);
}

Теперь, когда мы знаем тип ордера, решаем, будем ли мы запрашивать его тикет. Если мы отслеживаем лонги, а функция вернула нам значение = 1 (продажа), то ни чего не делаем, если же вернула нужное нам значение = 0 (покупка), то нам нужно запросить его тикет:

// =================== Hist_TicketLastOrdera() ======================================================
// Функция возвращает тикет последнего закрытого ордера
// -----------------------------------------
int Hist_TicketLastOrdera(string Type,int MAGIC){
        string NameFunction="Hist_TicketLastOrdera()";
        int Ticket=-1;
        string  SMB=Symbol();
        datetime        OrderTime=0;
        // ----------------- Обработка ошибок ------------------------
        if(Type!="BUY" && Type!="SELL" && Type!="BUYSTOP" && Type!="SELLSTOP" && Type!="BUYLIMIT" && Type!="SELLLIMIT"){
                Print("Некорректное значение переменной Type = ",Type);
                Print("Basic. Ошибка в функции ",NameFunction);
                return(-1);
        }
        for(int i=OrdersHistoryTotal()-1;i>=0;i--){
    if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)){
                        SelectError(i);
                        Print("Basic. Ошибка в функции ",NameFunction);
                }
    else{
      if(OrderSymbol()!= SMB || OrderMagicNumber()!= MAGIC){continue;}
      if(Type=="BUY"){
                                if(OrderType()!=OP_BUY){
                                        continue;
                                }
                                else{
                                        if(OrderTime<OrderCloseTime()){
                                                OrderTime=OrderCloseTime();
                                                Ticket=OrderTicket();
                                        }
                                }
                        }
                        if(Type=="SELL"){
                                if(OrderType()!=OP_SELL){
                                        continue;
                                }
                                else{
                                        if(OrderTime<OrderCloseTime()){
                                                OrderTime=OrderCloseTime();
                                                Ticket=OrderTicket();
                                        }
                                }
                        }
                        if(Type=="BUYSTOP"){
                                if(OrderType()!=OP_BUYSTOP){
                                        continue;
                                }
                                else{
                                        if(OrderTime<OrderCloseTime()){
                                                OrderTime=OrderCloseTime();
                                                Ticket=OrderTicket();
                                        }
                                }
                        }
                        if(Type=="SELLSTOP"){
                                if(OrderType()!=OP_SELLSTOP){
                                        continue;
                                }
                                else{
                                        if(OrderTime<OrderCloseTime()){
                                                OrderTime=OrderCloseTime();
                                                Ticket=OrderTicket();
                                        }
                                }
                        }
                        if(Type=="BUYLIMIT"){
                                if(OrderType()!=OP_BUYLIMIT){
                                        continue;
                                }
                                else{
                                        if(OrderTime<OrderCloseTime()){
                                                OrderTime=OrderCloseTime();
                                                Ticket=OrderTicket();
                                        }
                                }
                        }
                        if(Type=="SELLLIMIT"){
                                if(OrderType()!=OP_SELLLIMIT){
                                        continue;
                                }
                                else{
                                        if(OrderTime<OrderCloseTime()){
                                                OrderTime=OrderCloseTime();
                                                Ticket=OrderTicket();
                                        }
                                }
                        }
    }
  }
        return(Ticket);
}

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

Тут вот в чём фокус. Кто-то скажет, что я сделал слишком много телодвижений. Можно было проще, одним единственным циклом найти последний ордер истории и вернуть время его закрытия. Это верно, НО! это верно только для одного единственного советника. Функции же, которые я дал можно сунуть в библиотеку. Дальнейшая работа становится в разы проще. Одной строкой кода подключаем к будущему советнику нашу библиотеку, а двумя-тремя другими проводим вызов функций (читай, уже написанных ранее нами кодов), делаем нужные сравнения. В результате код советника получается маленький и хорошо читаемый, ибо основные функции лежат в нашей многоразовой библиотеке. Ну и раз логика советника отслеживается легче, то и допустить случайную ошибку становится труднее. Вобще, логические ошибки отследить труднее всего. Если ошибку синтаксическую компилятор покажет в лёгкую, то он ни как не сможет сказать Вам что вот тут нужно было сравнивать показания не индикаторов 1 и 2, а 1 и 3. Он не сможет отследить ошибки в Вашей логике кода. А когда код маленький, логику проверить проще, чем когда приходится копаться в тысячах строк кода.

 
Vitaly Murlenko #:

Довольно интересную тему поднял топикстартер. Я тоже пробовал разные варианты. За годы программирования уже сложился такой подход: Предположим у нас есть некий сигнал и по нему должен открыться один и только один ордер в нужную сторону. Я для осуществления этого сделал себе функцию "Счётчик ордеров". Скажем так, по лонговому сигналу должен открыться лонговый ордер. Делаем проверку: если счётчик лонговых ордеров = нулю, то открыть ордер. Пусть на данном тике ордер открылся. На следующем тике советник обнаружит снова лонговый сигнал, но счётчик скажет, что у нас уже есть рыночный лонг. Поэтому до тех пор, пока рыночный жив, ни по какому лонговому сигналу Бай-ордер больше не откроется.

Бывает, что время жизни ордера меньше времени жизни свечи (свечка ещё не закрылась, а ордер уже отработал). Ордер открылся, отработал, цена уехала. Ордера уже нет, а свечка ещё не закрылась и советник видит, что сигнал есть. В случае, если нам уже не выгодно открываться по такой цене (нужно было открываться на первых тиках), то встраиваю дополнительную проверку. Для этого я сделал себе функцию, возвращающую время закрытия последнего рыночного ордера. Итак, что имеем, если есть сигнал и нет ордера и при этом время закрытия последнего рыночного меньше времени открытия свечи (менее, чем Time[0]), то открываем позу.

Я писал такой же код по аналогичной логике. Все работает, это верно. Но. Время выполнения теста и оптимизации советника увеличивается в 5 раз с такой фукнцией. Это очень критично, когда оптимизируешь много параметров. 

Я все еще в поисках эффективного способа...

 

Под МТ5 если нужно переделайте, под МТ4 работает отлично

//+----------------------------------------------------------------------------+
//|  Описание : Возвращает номер бара открытия последней позиции или -1.       |
//+----------------------------------------------------------------------------+
//|  Параметры:                                                                |
//|    sy - наименование инструмента   ("" или NULL - текущий символ)          |
//|    tf - таймфрейм                  (    0       - текущий таймфрейм)       |
//|    op - операция                   (   -1       - любая позиция)           |
//|    mn - MagicNumber                (   -1       - любой магик)             |
//+----------------------------------------------------------------------------+
int NumberOfBarOpenLastPos(string sy="0", int tf=0, int op=-1, int mn=-1)
  {
   datetime t=0;
   int      i, k=OrdersTotal();

   if(sy=="" || sy=="0")
      sy=_Symbol;
   for(i=0; i<k; i++)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderSymbol()==sy)
           {
            if(OrderType()==OP_BUY || OrderType()==OP_SELL)
              {
               if(op<0 || OrderType()==op)
                 {
                  if(mn<0 || OrderMagicNumber()==mn)
                    {
                     if(t<OrderOpenTime())
                        t=OrderOpenTime();
                    }
                 }
              }
           }
        }
     }
   return(iBarShift(sy, tf, t, true));
  }
//--- End ---
Причина обращения: