Обучение языку MQL4 под MetaTrader 4📌

От xbms, 13 апреля, 2013 в Уголок Программиста

#6201

Всем доброго времени. Кто может поделиться частью кода для реверсивных сделок? Я создал 2 переменные, но они не работают(

Вот что я сделал:

Спойлер

bool     trade_flag_buy = true, trade_flag_sell = false; // в шапке изначально создаем типа переключателя, без разницы какая позиция первой будет
.............................
  //далее идет условие на открытие позиции
  if(
....... // ля ля ля
   trade_flag_buy
    )

  //открываемся в покупку
}
else
    if(
....... // ля ля ля
   trade_flag_sell
    )

  //открываемся в продажу
}

//+---------------------А вот здесь происходит сама инверсия --------------------+

   for(int t=OrdersHistoryTotal()-1; t>=0; t--)
     {
      if(OrderSelect(t, SELECT_BY_POS, MODE_HISTORY))
        {
         if(OrderSymbol()==Symbol())
           {
            if(OrderType() == OP_BUY)
              {
               trade_flag_buy=false;
               trade_flag_sell=true;
              }

            if(OrderType() == OP_SELL)
              {
               trade_flag_sell=false;
               trade_flag_buy=true;
              }
           }
        }
     }
 

Где может быть ошибка?

#6202
9 часов назад, diodio сказал:

Где может быть ошибка?

Цикл по истории будет всегда возвращать тип ордера первой позиции в истории.
Внутри цикла нужно добавить проверку (сравнение) ордеров по какому-либо критерию (время открытия или время закрытия или тикет)
 

Спойлер

//+---------------------А вот здесь происходит сама инверсия --------------------+
   int ord_type_tmp;
   datetime close_time_prev;

   for(int t=OrdersHistoryTotal()-1; t>=0; t--)
     {
      if(OrderSelect(t, SELECT_BY_POS, MODE_HISTORY))
        {
         if(OrderSymbol()==Symbol() && OrderMagic()==Magic)
           {
              if(OrderCloseTime() > close_time_prev) 
              {
                ord_type_tmp = OrderType();
                close_time_prev = OrderCloseTime();
              }
           }
        }
     }

     if(ord_type_tmp == OP_BUY)
     {
         trade_flag_buy=false;
         trade_flag_sell=true;
     }
     else if(ord_type_tmp == OP_SELL)
     {
        trade_flag_sell=false;
        trade_flag_buy=true;
     } 

 

 

#6203

Здравствуйте!

 

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

 

for (int j = 0; j<ArrayRange(prices, 0); j++)
    {
      double result = 0;
      if (prices[j][0] > 0)
      if ((prices[j][5] + prices[j+1][5]) > 20)  // возможно вот здесь проблема!
      {
        result = (prices[j][5] + prices[j+1][5]); //в result выводит найденные значения которые выше 20, а нужно чтобы выводила результат сложения.
        Print("index ", prices[j][0], " open ", prices[j][1], " high ", prices[j][2], 
        "\n low ", prices[j][3], " close ", prices[j][4], " result ",  result);
      }
    }
  } //end-for;
}

Помогите пожалуйста разобраться. Ниже скрин отображения информации.

 

 

 

 

array_sum_fix.png

#6204
5 часов назад, Alexfm2000 сказал:

Записать результат сложения в двухмерном массиве

Вы пишете в журнал значение result на каждой итерации цикла.
И каждую итерацию Вы эту переменную обнуляете (объявляете).
Если нужна сумма всех значений, то :
1. double result = 0; нужно объявить ДО цикла for
2. записать

result = result + (prices[j][5] + prices[j+1][5]);

3. Print() написать после окончания цикла

#6205
54 минуты назад, usver73 сказал:

Вы пишете в журнал значение result на каждой итерации цикла.
И каждую итерацию Вы эту переменную обнуляете (объявляете).
Если нужна сумма всех значений, то :
1. double result = 0; нужно объявить ДО цикла for
2. записать


result = result + (prices[j][5] + prices[j+1][5]);

3. Print() написать после окончания цикла

usver73 спасибо большое! 

Есть прогресс, теперь суммирует все значения в переменную result например которые больше 20 пунктов. А как можно ограничить чтобы записывало только 2 макс. 3 бара которые в сумме выше проверяемого числа? 

вот весь код, код ещё не доработан

void Prices()
{
  double result = 0; //кол-во пунктов
  for (int i = 1; i < barshift2; i++)
  {
    int index = 0;
    index++;
    prices[index][0] = i;
    prices[index][1] = Open[i];
    prices[index][2] = High[i];
    prices[index][3] = Low[i];
    prices[index][4] = Close[i];
    prices[index][5] = int((High[i] - Low[i])/Point/10);
    
    for (int j = 0; j<ArrayRange(prices, 0); j++)
    {
      
      if (prices[j][0] > 0)
      if ((prices[j][5] + prices[j+1][5]) > 20) 
      {
        result = result + (prices[j][5] + prices[j+1][5]);
        Print("index ", prices[j][0], " open ", prices[j][1], " high ", prices[j][2], 
        "\n low ", prices[j][3], " close ", prices[j][4]);
      } 
    }
  } //end-for;
   Print( " result ",  result);
}

 

#6206
Только что, Alexfm2000 сказал:

А как можно ограничить чтобы записывало только 2 макс.

Фиг знает... 
На ум с первой прикидки приходит идея делать несколько циклов по массиву.. Но что-то подсказывает, что это неоптимально...
Наверняка есть функции (погуглить) сортировки массива. После сортировки брать ХХ первых (последних) значений..

    int index = 0;
    index++;
    prices[index][0] = i;
    prices[index][1] = Open[i];
    prices[index][2] = High[i];
    prices[index][3] = Low[i];
    prices[index][4] = Close[i];
    prices[index][5] = int((High[i] - Low[i])/Point/10);

в чем смысл этого куска я не понял.. index всегда будет = 1. Соответственно, следующий цикл будет перебирать весь массив, но только в [1][] будут какие-то осмысленные значения...
Если Вы хотите получить Макс/Мин цены за некий период, то смотрите в сторону стандартных функций из раздела

Справочник MQL4 / Доступ к таймсериям (iHigh(), iHighest() и т.п.
#6207
15 минут назад, usver73 сказал:

Фиг знает... 
На ум с первой прикидки приходит идея делать несколько циклов по массиву.. Но что-то подсказывает, что это неоптимально...
Наверняка есть функции (погуглить) сортировки массива. После сортировки брать ХХ первых (последних) значений..

в чем смысл этого куска я не понял.. index всегда будет = 1. Соответственно, следующий цикл будет перебирать весь массив, но только в [1][] будут какие-то осмысленные значения...
Если Вы хотите получить Макс/Мин цены за некий период, то смотрите в сторону стандартных функций из раздела

Справочник MQL4 / Доступ к таймсериям (iHigh(), iHighest() и т.п.

По поводу сортировки массива он уже отсортирован в prices[index][0] oн по попорядку идёт.

В prices[index][5] длина  каждой свечи от low до high в пунктах. Нужно теперь проверить если длина prices[j][5] + длина второй свечи prices[j+1][5] больше значения n (в пунктах) то сохранить сумму этих двух баров в переменную result. после этого break; тоесть чтобы не суммировала все остальные бары которые выше заданного значения n.

 

по поводу index сюда записываются все индексы свечей по порядку, то есть, если к примеру barshift на 20 или 100 свечей то в нулевом индексе будут записаны индекс свечей по порядку от 1 до 100.

#6208
Только что, Alexfm2000 сказал:

По поводу сортировки массива он уже отсортирован в prices[index][0] oн по попорядку идёт.

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

Только что, Alexfm2000 сказал:

по поводу index сюда записываются все индексы свечей по порядку,

И, да- не записываются значения 20 или 100 свечей в массив. Вы index все время обнуляете внутри цикла.
Вынесите его наружу цикла...

И вообще- нафига записывать параметры свечей в массив, если есть функции, о которых я писал ранее?!

#6209
16 минут назад, usver73 сказал:

Вам виднее, но я говорил о сортировке по значению, а Вы , видимо, имеете ввиду сортировку по некоему порядку (подозреваю, что по порядку следования свечей).

Да всё верно. по порядку следования свечей, ну хорошо попробую погуглить по поводу сортировки. 

Спасибо за вашу помощь!

#6210
В 25.02.2021 в 09:00, usver73 сказал:

Цикл по истории будет всегда возвращать тип ордера первой позиции в истории.
Внутри цикла нужно добавить проверку (сравнение) ордеров по какому-либо критерию (время открытия или время закрытия или тикет)
 

  Показать контент


//+---------------------А вот здесь происходит сама инверсия --------------------+
   int ord_type_tmp;
   datetime close_time_prev;

   for(int t=OrdersHistoryTotal()-1; t>=0; t--)
     {
      if(OrderSelect(t, SELECT_BY_POS, MODE_HISTORY))
        {
         if(OrderSymbol()==Symbol() && OrderMagic()==Magic)
           {
              if(OrderCloseTime() > close_time_prev) 
              {
                ord_type_tmp = OrderType();
                close_time_prev = OrderCloseTime();
              }
           }
        }
     }

     if(ord_type_tmp == OP_BUY)
     {
         trade_flag_buy=false;
         trade_flag_sell=true;
     }
     else if(ord_type_tmp == OP_SELL)
     {
        trade_flag_sell=false;
        trade_flag_buy=true;
     } 

 

 

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

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

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

Спойлер

//+---------------------Здесь инверсия открытия ордеров --------------------+

   for(int t = 0; t < OrdersHistoryTotal(); t++)
     {
      if(OrderSelect(t, SELECT_BY_POS, MODE_HISTORY))
        {
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==Magic)
           {
            if(OrderCloseTime() > close_time_prev)
              {
               ord_type_tmp = OrderType();
               close_time_prev = OrderCloseTime();
              }
           }
        }
     }

   if(ord_type_tmp == OP_BUY && trade_flag_buy && trade_flag_sell == false)
     {
      trade_flag_buy=false;
      trade_flag_sell=true;
     }
   else
      if(ord_type_tmp == OP_SELL && trade_flag_sell && trade_flag_buy == false)
        {
         trade_flag_sell=false;
         trade_flag_buy=true;
        }
 

 

#6211
13 минут назад, diodio сказал:

должна наверное быть логическая только ошибка.

Есть же универсальное средство отладки- Print

Впиши после цикла, например, тикет ордера. Это покажет- верно ли находится последний ордер.
Если не поможет, то впиши внутри цикла перед if(OrderCloseTime() > close_time_prev)- какие значения сравниваются...
Методом тыка, путем переставления строчек кода можно долго искать- где ошибка

#6212
3 часа назад, usver73 сказал:

Есть же универсальное средство отладки- Print

Впиши после цикла, например, тикет ордера. Это покажет- верно ли находится последний ордер.
Если не поможет, то впиши внутри цикла перед if(OrderCloseTime() > close_time_prev)- какие значения сравниваются...
Методом тыка, путем переставления строчек кода можно долго искать- где ошибка

Оказалось что переключатель не успевает переключиться как открывается повторная позиция с тем же типом. Думаю ставить sleep  после закрытия, только вот сколько?

#6213
Только что, diodio сказал:

Думаю ставить sleep  после закрытия, только вот сколько?

Нужно код смотреть целиком.
Вообще то так не должно быть- код исполняется последовательно.
Подожди.. У тебя просто переворотная система?
Тогда можно писать без анализа истории.
В момент открытия ордера пишешь в переменную его тип.
Если ордер закрылся (OrdersTotal()==0 или правильнее CountOrders()==0), то открываешь противоположный

Изменено 1 марта, 2021 пользователем usver73

#6214
3 часа назад, usver73 сказал:

Нужно код смотреть целиком.
Вообще то так не должно быть- код исполняется последовательно.
Подожди.. У тебя просто переворотная система?
Тогда можно писать без анализа истории.
В момент открытия ордера пишешь в переменную его тип.
Если ордер закрылся (OrdersTotal()==0 или правильнее CountOrders()==0), то открываешь противоположный

Дело в том что позиция не просто так открывается а на основании некоторых "Если...". Я вот тоже так подумал что не может быть чтоб так пропускало, ведь код читается сверху вниз и слева направо, так его читает машина. Когда наблюдал в живую именно этот момент переключения флажков, я увидел первое действие: была закрыта позиция на бай, в ту же секунду была опять выставлена позиция на бай и за этим действием в доли секунды переключились флажки так как было задуманно. Вообщем неуспели)

Я сделал проще но еще не проверял:

Спойлер

for(int r=OrdersTotal()-1; r>=0; r--)
     {
      if(OrderSelect(r, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderSymbol()==Symbol())
           {
            if(OrderType() == OP_BUY)
              {
               if(OrderClose(OrderTicket(), OrderLots(), Bid, Slippage))
                 {
                  Sleep(5000);
                 }
              }

            if(OrderType() == OP_SELL)
              {
               if(OrderClose(OrderTicket(), OrderLots(), Ask, Slippage))
                 {
                  Sleep(5000);
                 }
              }
           }
        }
     }

 

Изменено 1 марта, 2021 пользователем diodio

#6215
9 часов назад, diodio сказал:

Я сделал проще но еще не проверял:

т.е. фразу про переворотную систему пропустил... ну да бог с ней.
Этот код полезен, если ордера принудительно закрываются.
Если по ТП/СЛ, то паузы не будет....
И нафига все таки два bool- флага, если они всегда в инверсии относительно друг друга? Это чтобы проще ошибку сделать? :)

Изменено 2 марта, 2021 пользователем usver73

#6216
4 часа назад, usver73 сказал:

т.е. фразу про переворотную систему пропустил... ну да бог с ней.
Этот код полезен, если ордера принудительно закрываются.
Если по ТП/СЛ, то паузы не будет....
И нафига все таки два bool- флага, если они всегда в инверсии относительно друг друга? Это чтобы проще ошибку сделать? :)

Да, получилось теперь так, переворот есть и строго идет бай-сел чередованием, теперь не открывает 2 бая или села подряд, а открывает один и тут же закрывает. 2 флага написал думал что будут чередоваться, они чередуются, хотя можно обойтись и одним флагом, пока не знаю как ( А вот насчет закрытия по ТП тут да, паузы получается нет, и как же мне ее поставить?

Логика была такова что если есть в рынке ордер и он закрылся по ТП то тут же сработал переключатель, но на практике сразу закрывает после открытия и переключается. Как поставить задержку после достижения ТП?

#6217
4 часа назад, diodio сказал:

Да, получилось теперь так, переворот есть и строго идет бай-сел чередованием, теперь не открывает 2 бая или села подряд, а открывает один и тут же закрывает. 2 флага написал думал что будут чередоваться, они чередуются, хотя можно обойтись и одним флагом, пока не знаю как ( А вот насчет закрытия по ТП тут да, паузы получается нет, и как же мне ее поставить?

Логика была такова что если есть в рынке ордер и он закрылся по ТП то тут же сработал переключатель, но на практике сразу закрывает после открытия и переключается. Как поставить задержку после достижения ТП?

надо попробовать перед открытием позиции поставить задержку, должно сработать)

#6218
2 часа назад, diodio сказал:

надо попробовать перед открытием позиции поставить задержку, должно сработать)

Невнимательно читал предыдущие посты...

Флаг нужно ставить ПЕРЕД открытием ордера. Или сразу после его открытия,  если прошло все штатно. 

bool ordBuy =true; объявить на глобальном уровне 

Далее,  как правило,  на каждом тике считается количество ордеров в рынке.

Если количество бай+селл=0, значит произошло закрытие.  И не важно по тп, сл или принудительно.

Значит можно открывать ордер.

И здесь пишем примерно:

if(ordBuy) OpenOrder (sell); ordBuy =false;

else OpenOrder(buy); ordBuy =true;

 

Это схематично 

 

#6219
14 часов назад, usver73 сказал:

Невнимательно читал предыдущие посты...

Флаг нужно ставить ПЕРЕД открытием ордера. Или сразу после его открытия,  если прошло все штатно. 

bool ordBuy =true; объявить на глобальном уровне 

Далее,  как правило,  на каждом тике считается количество ордеров в рынке.

Если количество бай+селл=0, значит произошло закрытие.  И не важно по тп, сл или принудительно.

Значит можно открывать ордер.

И здесь пишем примерно:

if(ordBuy) OpenOrder (sell); ordBuy =false;

else OpenOrder(buy); ordBuy =true;

Все работает, поставил перед открытием ордера и после того как открылся ордер. А функция Sleep оказывается останавливает весь код на этом моменте где Sleep и далее он не читается пока не пройдет указанный интервал, поэтому после достижения ТП открывались сразу повторные позиции, а я ошибочно думал.

Спасибо, помог.

#6220
27 минут назад, diodio сказал:

поставил перед открытием ордера и после того как открылся ордер.

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

#6221
39 минут назад, usver73 сказал:

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

Спойлер

if(CountTrades()==0)
        {
         if(
            .....
                 trade_flag_buy == true
            && trade_flag_sell == false
         )
           {
            ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,0,0,comment,Magic,0,clrBlue); //открываем покупку
            if(ticket>0)
              {
               TP=NormalizeDouble(Ask+TakeProfit*Point,Digits); // назначаем ему тейкпрофит
               bool res=OrderModify(ticket,OrderOpenPrice(),0,TP,0);//модифицируем ордер
               trade_flag_buy = false;
               trade_flag_sell = true;
              }
           }
         else
            if(

               .....
                    trade_flag_buy == false
               && trade_flag_sell == true
            )
              {
               ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,0,0,comment,Magic,0,clrRed); //открываем продажу
               if(ticket>0)
                 {
                  TP=NormalizeDouble(Bid-TakeProfit*Point,Digits); // назначаем ему тейкпрофит
                  bool ressel=OrderModify(ticket,OrderOpenPrice(),0,TP,0);//модифицируем ордер
                  trade_flag_buy = true;
                  trade_flag_sell = false;
                 }
              }
        }

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

#6222

Привет. Задание к первому уроку
Напишите программу (советник), который в зависимости от заданной во внешних параметрах переменной X, выведет информацию в виде сообщения (Алерта), комментария на экране и комментария в логах одновременно, следующего содержания: При X = 0, то отобразить «TradeLikeAPro forever…», а при X=1 — «Insta must die!».

Не до конца понимаю архитектуру, в функции void OnTick() написал:
  {
      bool x = 1;
      
      if (x = 1)
      {
         Print("«Insta must die!»");
      } else
      {
         Print("«TradeLikeAPro forever…»");
      }
  }

Что надо исправить? Вынести ещё надо х в extern

 

#6223
1 час назад, finish_him сказал:

Что надо исправить? Вынести ещё надо х в extern

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

Делать его в функции обработки событий OnTick не целесообразно, потому что оно будет каждый тик спамить эту информацию. Поэтому вот вариант в функции OnInit.

#property copyright "Copyright (c) ReVeR27"
#property version   "1.00"
#property strict

extern int x = 0;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {

   string q = "";
   if(x == 1) q = "Insta must die!";
   else if(x == 0) q = "TradeLikeAPro forever";

   Comment(q);  
   Print(q);
   Alert(q);
   
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   Comment(""); 
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
      
  }
//+------------------------------------------------------------------+

 

#6224

Всем доброго времени суток! Такой вопрос имеется, при простановке тейкпрофита ордер доходя до нужной отметки ТП не закрывает, у меня тейк стоит в пунктах:

 

TP=NormalizeDouble(Ask+TakeProfit*Point,Digits);

 

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

 

Есть вариант такой:

 

TP = OrderOpenPrice() * OrderLots() + (OrderSwap() + OrderCommission())*TakeProfit * Point;

 

А потом его модификация:

 

bool res=OrderModify(ticket,OrderOpenPrice(),0,TP,0);

 

Правильно будет?

Изменено 15 марта, 2021 пользователем diodio

#6225
  • @diodio ПРиветствую. Ордера закрываются исключительно по Тейк-профиту или Стоп-лоссу. Никакие свопы, комиссии, даже спред не влияют* на закрытие ордера, их не нужно учитывать.
  • Не забываем, что покупки открываются по Аску, а закрываются по Биду
  • И на оборот, продажи открываются по Биду, а закрываются по Аску.
  • Значит цена не дошла до Тейк-профита или Стоп-лосса. Если это робот еще может быть не правильно указана цена.

 

П.С. * свопы, комиссии, даже спред нужно учитывать что бы сделка выходила в плюс т.е в прибыль. Но они ни какого влияния не имеют на закрытие ордера.

Для публикации сообщений создайте учётную запись или авторизуйтесь

Перейти к списку тем
Форум · 2.0.20260627.0025