Любые вопросы новичков по MQL4 и MQL5, помощь и обсуждение по алгоритмам и кодам - страница 380

 
Всем привет.
Впервые на форуме, если что-то делаю на форуме криво - заранее прошу извинить.
Давно смотрю на графики с индикаторами. Недавно слил 2 депозита. Перед открытием нового счета хочу проверить на истории прибыльность стратегии. На демо счету в МТ4.
Я вообще не программер. Умею только устанавливать сторонние индикаторы в МТ4 и, может быть, поменять толщину линии индикатора в MetaEditor (цвет в коде индикатора поменять уже скорее всего не смогу - только в терминале).
Скажите пож-та, есть где-то доходчиво изложенная инф. для человека с моими познаниями, с чего пошагово начать тестирование (в просторечье "инструкция для негров как пользоваться унитазом")? Индикаторов в стратегии 3 шт: МА (3 шт простые), Стохастик со стандартными уровнями, и CCI с 5-тью уровнями. Открытие коротких сделок после пересечения уровней индикаторов сверху вниз, длинных - наоборот (наверно понятно..). Установка тэйков и лосей.
Хотелось бы иметь возможность как визуального отслеживания работы стратегии в авто-режиме, так и без визуализации для подбора параметров индикаторов и ордеров.
 
ZebStamp:
Всем привет.
Впервые на форуме, если что-то делаю на форуме криво - заранее прошу извинить.
Давно смотрю на графики с индикаторами. Недавно слил 2 депозита. Перед открытием нового счета хочу проверить на истории прибыльность стратегии. На демо счету в МТ4.
Я вообще не программер. Умею только устанавливать сторонние индикаторы в МТ4 и, может быть, поменять толщину линии индикатора в MetaEditor (цвет в коде индикатора поменять уже скорее всего не смогу - только в терминале).
Скажите пож-та, есть где-то доходчиво изложенная инф. для человека с моими познаниями, с чего пошагово начать тестирование (в просторечье "инструкция для негров как пользоваться унитазом")? Индикаторов в стратегии 3 шт: МА (3 шт простые), Стохастик со стандартными уровнями, и CCI с 5-тью уровнями. Открытие коротких сделок после пересечения уровней индикаторов сверху вниз, длинных - наоборот (наверно понятно..). Установка тэйков и лосей.
Хотелось бы иметь возможность как визуального отслеживания работы стратегии в авто-режиме, так и без визуализации для подбора параметров индикаторов и ордеров.

при создании графического объекта (ГО), например ТрендЛине, выбираете цвет. При повторном создании ТрендЛине создается этим же цветом. Для Hline - выбрали цвет - и следующая такая. Берите желтый, голубой, ...

Если ГО создает советник, индикатор, скрипт - то как в программе напишете. Иногда выбор параметрами

 
STARIJ:

Если Вы думаете, что кто-то, глядя на Ваш код, может быстро найти ошибка - заблуждаетесь. Ошибки ищет компилятор. Текст программы должен быть отформатирован - для этого в MetaEditor есть стилизатор. Если Вам нравится другой стиль - используйте, например, программу AStyle.exe. После стилизации вы быстро увидите, что в программе 1) лишняя закрывающая скобка. 2) Объявлена переменная:     datetime date_Buf_1; // массив дат индикатора   - чтоб это был массив, надо [размер] или [] для динамического массива и потом размер задать ArrayResize кажется. И это нужно делать до использования массива - смотрите про это посты выше. 3) FileOpen(InpDirectoryName+"//"+InpFileName - кажется, палки надо наклонить в другую сторону. А лучше обойтись без InpDirectoryName+"//" - в папке Files и так файл найдете.

на строку: int copied=CopyTime(NULL,0,0,0,date_Buf_1); Компилятор злится, начало=конец=0   количество=0


Спасибо. Что-то получилось исправить, но больше интуитивно, чем пониманием. Но, все равно 3 ошибки лезут, касательно массива:

'Buf_1' - array required 111.mq4 93 21

'date_Buf_1' - array required 111.mq4 94 21

'Buf_1' - array required 111.mq4 100 16


//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
input string             InpFileName="111.csv";      // Имя файла 
input string             InpDirectoryName="Data";     // Имя каталога 

datetime Время=0;   // Время прошлого бара
double Bid1;
double   Buf_1[];
// double ExtBuffer;
long V1; // объем для текущего тика вверх
long V2; // накопленный объем для всех тиков вверх текущего бара
long V3; // объем текущего тика вниз
long V4; // накопленный объем для всех тиков вниз для текущего бара
long V5;  // отрицательные и положительные iVolume нарастающим итогом
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnInit()
  {
   IndicatorDigits(0);
   SetIndexBuffer(0,Buf_1);
//SetIndexBuffer(1,Buf_2);
   Bid1=Bid;
   V5=0;

  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   datetime Вр=Time[0];   // Время текущего бара
   if(Вр>Время)           // Если новый бар
     {
      Время=Вр;           // Запомнить
                          //      Buf_1[0]=0;         // и обнулить последний элемент буфера
     }

   datetime date_Buf_1[]; // массив дат индикатора 
   datetime time_Buf_1[]; // массив времени 
                          // --- считаю объем для положительных и отрицательных тиков      
   if(Bid>=Bid1)
     {
      if(Bid>Bid1) // если тик положительный..
        {
         V1=iVolume(NULL,0,0); // если повышающий цену тик, то находим его объем
         V2= V1 + V2;
        }
      else
        {
         V1=0;                // если Bid1 = Bid2, т.е. изменение цены = 0, то iVolume этого тика присваиваем 0;
         V2= V1 + V2;
        }
     }
   else
     {
      V3 = iVolume(NULL, 0, 0); // если понижающий цену тик 
      V4 = V3 + V4;             // то находим его объем  
     }

   V5=V2-V4;               // определяем разницу (дельту) между объемами положительных и отрицательных тиков
   Bid1=Bid;
   Buf_1[0]=V5; // в буфер сгружаем  дельту

                //   ExtBuffer = Buf_1 [0];
//   double macurrent=iMAOnArray(ExtBuffer,0,5,0,MODE_LWMA,0); 

// запись в файл данных буфера


//--- установим для массивов признак таймсерии 
   ArraySetAsSeries(Buf_1[0],true);
   ArraySetAsSeries(date_Buf_1[0],true);

//--- скопируем таймсерию 
   int copied=CopyTime(NULL,0,10000,0,date_Buf_1);

//--- подготовим массив Buf_1 
   ArrayResize(Buf_1[0],copied);

//--- скопируем значения линии индикатора  
   for(int i=0;i<copied;i++)
     {
      Buf_1[i]=V5;
     }
//--- откроем файл для записи значений индикатора 
   ResetLastError();
   int file_handle=FileOpen(InpDirectoryName+"//"+InpFileName,FILE_READ|FILE_WRITE|FILE_CSV);
   if(file_handle!=INVALID_HANDLE)
     {
      PrintFormat("Файл %s открыт для записи",InpFileName);
      PrintFormat("Путь к файлу: %s\\Files\\",TerminalInfoString(TERMINAL_DATA_PATH));
      //--- сначала запишем значения индикатора 
      FileWrite(file_handle,Buf_1[0]);
      //--- запишем время и значения в файл 
      for(int i=0;i<Buf_1[0];i++)
         FileWrite(file_handle,time_Buf_1[0],Buf_1[0]);
      //--- закрываем файл 
      FileClose(file_handle);
      PrintFormat("Данные записаны, файл %s закрыт",InpFileName);
     }
   else
      PrintFormat("Не удалось открыть файл %s, Код ошибки = %d",InpFileName,GetLastError());

   return(rates_total);
  }
//+------------------------------------------------------------------+


Не понял я, как Ваши замечания претворить в жизнь. Но, лишнюю скобу нашел :)
 
YarTrade:

Спасибо. Что-то получилось исправить, но больше интуитивно, чем пониманием. Но, все равно 3 ошибки лезут, касательно массива:

'Buf_1' - array required 111.mq4 93 21

'date_Buf_1' - array required 111.mq4 94 21

'Buf_1' - array required 111.mq4 100 16



Не понял я, как Ваши замечания претворить в жизнь. Но, лишнюю скобу нашел :)
Оставьте только названия переменных-массивов. Уберите "[]" в тех строках кода, на которые указывает вам компилятор.
 
Artyom Trishkin:
Оставьте только названия переменных-массивов. Уберите "[]" в тех строках кода, на которые указывает вам компилятор.

Спасибо. Посмотрю что получилось в жизни. Что-то у меня большие сомнения что что-то запишется в файл :)

 

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

1. В режиме реальной торговли вылезала ошибка деления на ноль, хотя разумеется в коде деления на ноль не было и во время бектестов такого не появлялось. Решил проблему тем, что каждый делитель записывал как NormalizeDouble(x,Digits);

2. Не открылась сделка. Пятничный день прогнав на бектесте сделка открылась, а во время реальной торговли нет. При чем в журнале советника никаких ошибок не выдал. Вот тут я не знаю в чем может быть дело, но грешу на пару вещей. Во первых у меня висят предупреждения вида "return value of 'ordersend' should be checked", но если я правильно понимаю на выполнение кода это влиять не должно? Или же все дело в проскальзывании? У меня стоит 1, что вроде не особо и мало. Да и бар на котором должен был выполнять вход открылся без гэпа.

3. Из стандартного примера со скользяшками я взял строчку "if(Volume[0]>1) return;" и вставил в начало кода. То есть мой код выполняется только во время первого тика при появлении нового бара. Может ли такое быть, что бар открывается сразу с объемом и мой код не выполняется?

4. Посоветуйте моменты на которые надо обратить внимание или типичные ошибки, при работе советника с историей и реальным временем, пожалуйста


 
LuckySith:

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

1. В режиме реальной торговли вылезала ошибка деления на ноль, хотя разумеется в коде деления на ноль не было и во время бектестов такого не появлялось. Решил проблему тем, что каждый делитель записывал как NormalizeDouble(x,Digits);

2. Не открылась сделка. Пятничный день прогнав на бектесте сделка открылась, а во время реальной торговли нет. При чем в журнале советника никаких ошибок не выдал. Вот тут я не знаю в чем может быть дело, но грешу на пару вещей. Во первых у меня висят предупреждения вида "return value of 'ordersend' should be checked", но если я правильно понимаю на выполнение кода это влиять не должно? Или же все дело в проскальзывании? У меня стоит 1, что вроде не особо и мало. Да и бар на котором должен был выполнять вход открылся без гэпа.

3. Из стандартного примера со скользяшками я взял строчку "if(Volume[0]>1) return;" и вставил в начало кода. То есть мой код выполняется только во время первого тика при появлении нового бара. Может ли такое быть, что бар открывается сразу с объемом и мой код не выполняется?

4. Посоветуйте моменты на которые надо обратить внимание или типичные ошибки, при работе советника с историей и реальным временем, пожалуйста

Замените такие дикие конструкции "if(Volume[0]>1) return;" на нормальную проверку "Нового бара", здесь на форуме их полно.

Предупреждения вида "return value of 'ordersend' should be checked" - это пока не ошибка, это потенциальная ошибка на будущее. В коде не должно быть никаких предупреждений, а тем более при работе онлайн.

"У меня стоит 1, что вроде не особо и мало" - этого может быть очень мало на открытии нового бара, а тем более получасового, и часового, в это время сильно расширяется спред.

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

Что есть сейчас: if(Volume[0]>1) return; = если новый бар, то смотрим условия, условие не подошло == большой спред = выход снова в OnTick(), на следующем тике if(Volume[0]>1) return; уже не пропустит дальше, поэтому сделка пропущена, даже если спред будет 0.0001

 

Здравствуйте. Подскажите пожалуйста, как мне с помощью кода описать следующее: Есть флет, ограниченный верхней и нижней горизонтальными линиями. Их советник определяет и устанавливает сам.

Нужно, чтобы советник определил выход цены из зоны флета, а затем возвращение в эту зону. И только после этого открывал позицию.

Для фильтрации шума использую мувинг с параметром 2 или3

 
Vitaly Muzichenko:

Замените такие дикие конструкции "if(Volume[0]>1) return;" на нормальную проверку "Нового бара", здесь на форуме их полно.

Предупреждения вида "return value of 'ordersend' should be checked" - это пока не ошибка, это потенциальная ошибка на будущее. В коде не должно быть никаких предупреждений, а тем более при работе онлайн.

"У меня стоит 1, что вроде не особо и мало" - этого может быть очень мало на открытии нового бара, а тем более получасового, и часового, в это время сильно расширяется спред.

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

Что есть сейчас: if(Volume[0]>1) return; = если новый бар, то смотрим условия, условие не подошло == большой спред = выход снова в OnTick(), на следующем тике if(Volume[0]>1) return; уже не пропустит дальше, поэтому сделка пропущена, даже если спред будет 0.0001


Насчет открытия нового бара. Будет ли хорошим такой вариант? :

datetime counted_bar = 0;

int OnInit()
{
   counted_bar = 0; // если нужно, чтоб при перезапуске последний бар был проанализирован
   ...

void OnTick()
{
   // Если появился новый бар
   if ( iTime( _Symbol, _Period, 0 ) > counted_bar )
   {
      counted_bar = iTime( _Symbol, _Period, 0 );

      // Анализируем индикаторы
      ...
   }
 
LuckySith:

Насчет открытия нового бара. Будет ли хорошим такой вариант? :

Пусть будет изначально такая.

Далее, нужно сделать правильное фиксирование что бар отработан, но здесь нужно просчитать весь подход к ТЗ.

Пока то, что Я вижу с вашего поста, то нужно сделать так:

void OnTick()
{
   // Если появился новый бар
   if ( iTime( _Symbol, _Period, 0 ) > counted_bar )
   {
      // Анализируем индикаторы
      if(SpreadMax > текущий спред) return;

      counted_bar = iTime( _Symbol, _Period, 0 );
      ...
   }

Суть такая, что если спред больше нормы, значит выходим снова в OnTick, и на новом тике проверяем спред, если он нормальный - отправляем ордер и запоминаем, что на этом баре была сделка.

Можно ещё второй способ:

void OnTick()
{
   // Если появился новый бар
   if ( iTime( _Symbol, _Period, 0 ) > counted_bar )
   {
      if(SpreadMax > текущий спред) return;
      // Анализируем индикаторы
      ...
      result = OrderSend(...);
      // если открылась позиция, то result будет тикет позиции
       if(result>0) counted_bar = iTime( _Symbol, _Period, 0 );
   }

В общем, вам нужно определиться с логикой, когда должно записаться, и больше не проверятся до образования "Нового бара"

Причина обращения: