Вопросы от начинающих MQL5 MT5 MetaTrader 5 - страница 577

 
mila.com:

Отлично, ещё и с комментариями.

Благодарю.

Ещё вопрос.

Нельзя - ли сделать эмуляцию клика "мышки" по заданным координатам?

Если не обязательно именно делать это из MQL, посмотрите в сторону AutoIT, там вообще можно делать все, что угодно. Продукт бесплатен, для взаимодействия с MQL нужна всего одна DLL.
[Удален]  
mila.com:

Отлично, ещё и с комментариями.

Благодарю.

Ещё вопрос.

Нельзя - ли сделать эмуляцию клика "мышки" по заданным координатам?

Можно.

#define MK_LBUTTON     0x0001
#define WM_LBUTTONDOWN 0x0201
#define WM_LBUTTONUP   0x0202

struct POINT
{
   int x;
   int y;
};

#import "User32.dll"
   uint WindowFromPoint( int x, int y );
   uint PostMessageW( uint hWnd, uint Msg, uint wParam, uint lParam );
   int ScreenToClient( uint hWnd, POINT& lpPoint );
#import

int x = 1000;  // Экранные координаты
int y = 350;

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
   uint hwnd = WindowFromPoint( x, y ); // Получаем дескриптор окна в нужном месте
   
   if( hwnd ){
      POINT point;
      point.x = x;
      point.y = y;
      ScreenToClient( hwnd, point );  // Преобразуем экранные координаты в координаты рабочей области окна
      
      uint lParam = (point.y * 65536) + (point.x & 0xFFFF);  // Упаковываем координаты в 32-разрядное целое
      
      PostMessageW( hwnd, WM_LBUTTONDOWN, MK_LBUTTON, lParam ); // Посылаем сообщения от "мыши"
      PostMessageW( hwnd, WM_LBUTTONUP, MK_LBUTTON, lParam );
   }
}
 
Artyom Trishkin:
Ну я бы оформил всё это в функцию, и вызывал бы её когда мне это нужно - хоть на каждом тике (если оправдано и необходимо), хоть на открытии новой свечи - раз в час например, если на Н1 работаем.

Артем, я же правильно понимаю, что если у нас идет цикл:for(int i=0; i<copy_bars; i++)  и в него вложен for(int j=0; j<copy_bars; j++)  , где  if(j==i) continue; , 

то это будет значить, что подсчет идет параллельно и если у нас грубо 5 свечей, то сравнение будет идти:

1 с 1 - выбрасываем.

1 с 2й, 1 с 3й, 1 с 4й, 1 с 5й.

далее запустится цикл, где будет:

2я с 1й, 2я с 3й, 2я с 4й, 2я с 5й.

и так далее.

Так же будет? 

 
Andrey Koldorkin:

Артем, я же правильно понимаю, что если у нас идет цикл:for(int i=0; i<copy_bars; i++)  и в него вложен for(int j=0; j<copy_bars; j++)  , где  if(j==i) continue; , 

то это будет значить, что подсчет идет параллельно и если у нас грубо 5 свечей, то сравнение будет идти:

1 с 1 - выбрасываем.

1 с 2й, 1 с 3й, 1 с 4й, 1 с 5й.

далее запустится цикл, где будет:

2я с 1й, 2я с 3й, 2я с 4й, 2я с 5й.

и так далее.

Так же будет? 

Да.
 
Artyom Trishkin:
Да.

Еще вопрос: Если нам не нужно сравнивать текущую свечу, то разве нам не нужно запускать счет с 1, а не с нуля?

или надо понимать, что тут 0 - это свеча 1, 1 - это свеча 2 и т.д.? 

 
Andrey Koldorkin:

Еще вопрос: Если нам не нужно сравнивать текущую свечу, то разве нам не нужно запускать счет с 1, а не с нуля?

или надо понимать, что тут 0 - это свеча 1, 1 - это свеча 2 и т.д.? 

Тут ноль - это начало массива. А в массив мы пишем свечи от первой, до ..., не "до", а в нужном нам количестве:

int copied=CopyRates(Symbol(),PERIOD_CURRENT,1,copy_bars,array);

1 - это номер свечи, с которой начинаем копирование, а copy_bars - это количество свечей, которое нужно скопировать.

Поэтому в массиве array[] у нас содержится в ячейке с индексом 0 нужная нам свеча - либо 1, либо 1+copy_bars-1. в зависимости от направления индексации массива array[] (ArraySetAsSeries() задаёт направление индексации, которое можно проверить при помощи ArrayGetAsSeries(), ArrayIsSeries())

 
Artyom Trishkin:

Тут ноль - это начало массива. А в массив мы пишем свечи от первой, до ..., не "до", а в нужном нам количестве:

1 - это номер свечи, с которой начинаем копирование, а copy_bars - это количество свечей, которое нужно скопировать.

Поэтому в массиве array[] у нас содержится в ячейке с индексом 0 нужная нам свеча - либо 1, либо 1+copy_bars-1. в зависимости от направления индексации массива array[] (ArraySetAsSeries() задаёт направление индексации, которое можно проверить при помощи ArrayGetAsSeries(), ArrayIsSeries())

Ох уж это программирование. Чем дальше в лес.... 

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

Потом проверил через:

bool series=ArrayIsSeries(dataCandle);

Alert (series);

и Скрипт выдал "false"               

по моей логике, если false, это не с того конца, то true будет с того, что надо.

Я прописал:      

              ArraySetAsSeries (dataCandle, true);    //смена направления

              bool series=ArrayIsSeries(dataCandle); //заново проверяю что получилось

              Alert (series); //вывожу результат на экран.

Но все равно после этого я получаю "false" .

В чем мой косяк? 

               

 
Andrey Koldorkin:

Ох уж это программирование. Чем дальше в лес.... 

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

Потом проверил через:

bool series=ArrayIsSeries(dataCandle);

Alert (series);

и Скрипт выдал "false"               

по моей логике, если false, это не с того конца, то true будет с того, что надо.

Я прописал:      

              ArraySetAsSeries (dataCandle, true);    //смена направления

              bool series=ArrayIsSeries(dataCandle); //заново проверяю что получилось

              Alert (series); //вывожу результат на экран.

Но все равно после этого я получаю "false" .

В чем мой косяк? 

               

dataCandles - это структура. Массив, куда мы пишем сами свечи из истории - array[]. Вот его и нужно сделать как таймсерию чтобы его индексация совпадала с индексацией свечей на графике. Т.е., Нулевая ячейка массива array[] соответствовала бы ближайшим свечам к текущей дате.

Т.е., 1. копируем в массив array[] свечи, 2. делаем его таймсерией, потом считываем с него значения в структуру.

Можно было бы обойтись и без массива array[] - сразу писать данные прямо с графика в структуру, но я так предложил для совместимости с пятёркой - в ней можно так копировать напрямую только в индикаторе, используя high[i], low[i] и прочие данные, но в скрипте, или советнике, нам всё равно придётся сначала скопировать нужный отрезок истории в массив, что я сразу и сделал.

 
Artyom Trishkin:

dataCandles - это структура. Массив, куда мы пишем сами свечи из истории - array[]. Вот его и нужно сделать как таймсерию чтобы его индексация совпадала с индексацией свечей на графике. Т.е., Нулевая ячейка массива array[] соответствовала бы ближайшим свечам к текущей дате.

Т.е., 1. копируем в массив array[] свечи, 2. делаем его таймсерией, потом считываем с него значения в структуру.

Можно было бы обойтись и без массива array[] - сразу писать данные прямо с графика в структуру, но я так предложил для совместимости с пятёркой - в ней можно так копировать напрямую только в индикаторе, используя high[i], low[i] и прочие данные, но в скрипте, или советнике, нам всё равно придётся сначала скопировать нужный отрезок истории в массив, что я сразу и сделал.

               bool series=ArrayIsSeries(array);
               Alert (series);
               
               
              ArraySetAsSeries (array, true);
              bool series=ArrayIsSeries(array);

              Alert (series);

 

вот так?

все равно оба алерта выдают false 

 
Andrey Koldorkin:
               bool series=ArrayIsSeries(array);
               Alert (series);
               
               
              ArraySetAsSeries (array, true);
              bool series=ArrayIsSeries(array);

              Alert (series);

 

вот так?

все равно оба алерта выдают false 

Значит это баг, о котором следует сообщить в "Ошибки, баги, вопросы".

Вот проверочный скрипт, он показывает время скопированных свечей в нулевой и последней ячейках массива array[]:

//+------------------------------------------------------------------+
//|                                                     TestCopy.mq4 |
//|              Copyright 2016, Artem A. Trishkin, Skype artmedia70 |
//|                       https://login.mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, Artem A. Trishkin, Skype artmedia70"
#property link      "https://login.mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property strict
#property script_show_inputs

enum enumYN
  {
   enYes=1, // Да
   enNo=0,  // Нет
  };

//--- input parameters
input int Search_Period=10;   // Количество копируемых свечей
int searchPeriod=(Search_Period<1)?1:Search_Period;
input int Delta=2;            // Количество пунктов допуска
int delta=(Delta<0)?0:Delta;
input enumYN AsSeries=enYes;  // Массив array как таймсерия
MqlRates array[];             // Массив структур для копирования Open, High, Low, Close, Time
  
struct DataCandle             // Структура для хранения всех совпадений
  {
   int number_matched;           // Количество совпадений
   MqlRates reference_candle;    // Данные эталонной свечи
   MqlRates matched_candles[];   // Массив свечей, совпадающих с эталонной по нужному критерию 
  };
  DataCandle dataCandle[];    // Массив структур данных свечей и их совпадений
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   int copy_bars=(int)fmin(Search_Period,Bars(Symbol(),Period()));   // количество копируемых свечей
   int copied=CopyRates(Symbol(),PERIOD_CURRENT,1,copy_bars,array);  // копируем данные
   if(copied>0) {                                                    // если скопировали
      ArraySetAsSeries(array,AsSeries);                              // задаём массив как таймсерию или нет
      ArrayResize(dataCandle,copied);                                // задаём размер структуры равным числу скопированных данных
      ZeroMemory(dataCandle);                                        // Обнуляем данные в структуре
      //--- основной цикл по "эталонным" свечам в массиве array. Их параметры будем искать в доп. цикле
      for(int i=0; i<copy_bars-1; i++) {                             // цикл по скопированным данным от начала до "на один меньше размера массива"
         dataCandle[i].reference_candle.high=array[i].high;          // ищем этот high
         dataCandle[i].reference_candle.low=array[i].low;            // запомнили low для сравнения
         dataCandle[i].reference_candle.time=array[i].time;          // запомнили time для вывода в журнал
         //--- поиск совпадений с эталонной свечой, индексируемой индексом основного цикла i
         int size=0;                                                 // размер массива совпадающих свечей
         ArrayResize(dataCandle[i].matched_candles,size);            // Размер массива совпадений в ноль
         dataCandle[i].number_matched=size;                          // Инициализируем количество совпадений нулём
         //--- теперь ищем совпадения по high свечей в цикле j с high эталонной свечи с индексом i
         for(int j=0; j<copy_bars; j++) {                            // в цикле от i+1 до copy_bars
            if(j==i) continue;                                       // пропустим свечу "саму себя"
            //--- если совпадают high эталонной свечи (i) и свечи с индексом j (с допуском на величину Point)
            if(NormalizeDouble(delta*Point()-fabs(array[i].high-array[j].high),Digits())>=0) {
               size++;                                               
               ArrayResize(dataCandle[i].matched_candles,size);            // увеличим размер массива совпадающих свечей
               dataCandle[i].number_matched=size;                          // запишем количество совпадений
               dataCandle[i].matched_candles[size-1].high=array[j].high;   // запишем в массив high совпадающей свечи
               dataCandle[i].matched_candles[size-1].low=array[j].low;     // запишем в массив low совпадающей свечи
               dataCandle[i].matched_candles[size-1].time=array[j].time;   // запишем в массив время совпадающей свечи
               //Print("Время свечи ",i," :",TimeToString(dataCandle[i].reference_candle.time=array[i].time),", high=",DoubleToString(dataCandle[i].reference_candle.high=array[i].high,Digits()),". Совпадение со свечой ",TimeToString(dataCandle[i].matched_candles[size-1].time=array[j].time),", её high ",DoubleToString(dataCandle[i].matched_candles[size-1].high=array[j].high,Digits()),". Совпадений: ",(string)dataCandle[i].number_matched);
               }
            }
         }
      }

   //--- Посмотрим чего понаписали в массивы
   Alert("Array is series: ",ArrayIsSeries(array),
         "\ntime array[0]: ",TimeToString(array[0].time,TIME_DATE|TIME_MINUTES),
         "\ntime array[",string(searchPeriod-1),"]: ",TimeToString(array[ArraySize(array)-1].time,TIME_DATE|TIME_MINUTES));
   for(int i=0; i<ArraySize(dataCandle)-1; i++) {
      string refs_txt="";
      string matched_txt="";
      refs_txt="Свеча "+IntegerToString(i,2,'0')+": время "+TimeToString(dataCandle[i].reference_candle.time)+", high: "+DoubleToString(dataCandle[i].reference_candle.high,Digits())+" имеет совпадений: "+(string)dataCandle[i].number_matched+" шт. ";
      if(dataCandle[i].number_matched>0) {
         for(int j=0; j<ArraySize(dataCandle[i].matched_candles); j++) {
            matched_txt="Совпадение "+IntegerToString(j+1)+": "+TimeToString(dataCandle[i].matched_candles[j].time)+", high: "+DoubleToString(dataCandle[i].matched_candles[j].high,Digits());
            }
         }
      Print(refs_txt,matched_txt);
      }
  }
//+------------------------------------------------------------------+