Вопросы от начинающих MQL4 MT4 MetaTrader 4 - страница 137

 
Игорь Васильев:

Странно, почему компилятор не сообщает об этом, когда видит торговые команды в коде индикатора.

Придется теперь торговую часть вытащить из индикатора в советник, связав его с ним через ICustom(). 

Выглядит как "не пришей кобыле хвост и сбоку бант".

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

 

Всем привет! Подскажите пожалуйста возможно ли сделать следующее.

Есть структура, например:
// структура неких событий
struct MyStruct
{
    int Number;
    datetime DTm;
    double Value;
    string Type;
}

Объявляю динамический массив структур типа MyStruct:
MyStruct DataEvents[];

В некой функции формирую и заполняю массив, например:
void GetDataEventsTest(MyStruct& DataEvents[], int countEvent=5)
{
    MathSrand(GetTickCount());
    ArrayResize(DataEvents, countEvent);
    int i = 0;
    while( i<countEvent )
    {
        DataEvents.Number = i;
        DataEvents.DTm = TimeCurrent();
        DataEvents.Value = (double)MathRand();
        if( MathMod(i, 2)>0 ) DataEvents.Type = "Up"; else DataEvents.Type = "Dn";
        i = i + 1;
    }
}

Где-то заполняем массив вызывая GetDataEventsTest():
GetDataEventsTest(DataEvents);

Возникла необходимость, например в середину интервала элементов массива, где-то по индексу 2 вставить новый элемент типа MyStruct.
Логика подсказывает следующие действия:
ArrayResize(DataEvents, ArraySize(DataEvents)+1);
и что-то типа такое:
int iNew = 2;
int i = ArraySize(DataEvents) - 2;
while( i>=iNew )
{
    // DataEvents[i+1] = DataEvents[i]; // естественно не работает, так как нужно работать с адресами на которые указывает элемент массива, так
    // Элементу массива по DataEvents[i+1] = записать чтобы он указывал на элемент массива DataEvents[i];
    i = i - 1;
}
... далее заполняю элемент массива DataEvents[iNew] данными.


Вопрос возможно ли такое провернуть со структурами в mql4?

 
GitSM:

Вопрос возможно ли такое провернуть со структурами в mql4?

Да, возможно. Если бы структура была без сложного типа данных (здесь в нее входит string), то сразу бы все получилось. А когда в структуре присутствуют типы данных, размер данных в которых может изменяться с течением времени, нужно перегрузить оператор присваивания:

struct MyStruct
{
    int Number;
    datetime DTm;
    double Value;
    string Type;

    void operator = (const MyStruct &stMyStruct)
    {
      Number = stMystruct.Number;
      DTm = stMyStruct.DTm;
      Value = stMyStruct.Value;
      Type = stMyStruct.Type;
    }
}
 
Ihor Herasko:

Да, возможно. Если бы структура была без сложного типа данных (здесь в нее входит string), то сразу бы все получилось. А когда в структуре присутствуют типы данных, размер данных в которых может изменяться с течением времени, нужно перегрузить оператор присваивания:

Спасибо за подсказку!
 

Снова возник вопрос в том же направлении как и в прошлом примере.
Если структура сложная и может содержать в себе массивы с другие структуры. Например делаю такие объявления:

// элемент со свойствами
struct ItemProperty
{
    double Low;
    double High;
    double Middle;
    double Range;
    double Area;
    string Type;
   
    void operator = (const ItemProperty &SourceItemProperty)
    {
        Low = SourceItemProperty.Low;
        High = SourceItemProperty.High;
        Middle = SourceItemProperty.Middle;
        Range = SourceItemProperty.Range;
        Area = SourceItemProperty.Area;
        Type = SourceItemProperty.Type;
    }
}

// элементы со статистическими свойствами
struct ItemsProperty;
{
    double MinLow;
    double MaxHigh;
    double AvgRange;
    double AvgArea;
    string Phase;
   
    Item Items[];
   
    void operator = (const ItemProperty &SourceItemsProperty)
    {
        MinLow = SourceItemsProperty.MinLow;
        MaxHigh = SourceItemsProperty.MaxHigh;
        AvgRange = SourceItemsProperty.AvgRange;
        AvgArea = SourceItemsProperty.AvgArea;
        Phase = SourceItemsProperty.Phase;
       
        // Items = SourceItemProperty.Items; // Как сделать так чтобы на один и тот же физический массив в памяти могло указывать несколько переменных массива?
    }
}

// структура неких событий на основе анализа элементов
struct EventProperty
{
    int Number;
    datetime DTm;
    double Value;
    string Type;
   
    double Levels[];
    int Weigths[];
   
    ItemsProperty ItemsProp[];
   
    void operator = (const ItemProperty &SourceEventProperty)
    {
        Number = SourceEventProperty.Number;
        DTm = SourceEventProperty.DTm;
        Value = SourceEventProperty.Value;
        Type = SourceEventProperty.Type;

        // Levels = SourceEventProperty.Levels; // тут затык
        // Weigths = SourceEventProperty.Weigths; // эхххь

        // ItemsProp = SourceEventProperty.ItemsProp; // тут тоже проблемы

    }
}

Объявляю динамический массив событий:
EventProperty MyEvents[];

В какой-нибудь функции заполняю данные массива событий.
void GetEventsProperty(EventProperty& MyEvents)
{
    // код заполнения
}

и где-то возникает необходимость манипулировать элементами массива MyEvents, добавляя или удаляя их.

int iNew = 2;
int i = ArraySize(MyEvents) - 2;
while( i>=iNew )
{
    // MyEvents[i+1] = MyEvents[i]; // и тут затык
    i = i - 1;
}

Можно ли провернуть такое с массивом структур в мт4? Получается необходимо иметь возможность ссылаться на один и тот же элемент массива структур в памяти с разных переменных-ссылок, создавая и удаляя их.
Можно ли работать с массивом ссылок на структуры?

 
GitSM:

Можно ли провернуть такое с массивом структур в мт4? Получается необходимо иметь возможность ссылаться на один и тот же элемент массива структур в памяти с разных переменных-ссылок, создавая и удаляя их.

Можно ли работать с массивом ссылок на структуры?

По идее должно быть так:

struct ItemsProperty;
{
    double MinLow;
    double MaxHigh;
    double AvgRange;
    double AvgArea;
    string Phase;
    
    Item Items[];
    
    void operator = (const ItemProperty &SourceItemsProperty)
    {
        MinLow = SourceItemsProperty.MinLow;
        MaxHigh = SourceItemsProperty.MaxHigh;
        AvgRange = SourceItemsProperty.AvgRange;
        AvgArea = SourceItemsProperty.AvgArea;
        Phase = SourceItemsProperty.Phase;
 
        int nTotal = ArraySize(SourceItemProperty.Items);
        ArrayResize(Items, nTotal);
        for (int i = 0; i < nTotal; ++i)
           Items[i] = SourceItemProperty.Items[i];
    }
}

И со всеми остальными массивами точно также. Вопрос:

Как сделать так чтобы на один и тот же физический массив в памяти могло указывать несколько переменных массива?

не понял.

P. S. Для вставки кода используйте пиктограмму "</>" или Alt+S.

 

Как сделать так чтобы на один и тот же физический массив в памяти могло указывать несколько переменных массива?

не понял.

Извините, не совсем корректно сформулировал вопрос. Если я правильно понимаю, массив структур по сути есть ссылки-адреса по индексам массива, каждая из которых указывает на какой-то физический адрес в памяти, распределённый определённым образом в соответствии со структурой данных. Под "Как сделать так чтобы на один и тот же физический массив в памяти могло указывать несколько переменных массива?" имел ввиду возможность сделать так чтобы например MyEvents[2] и MyEvents[5] указывали на одну и ту же структуру в памяти, то есть MyEvents[2] и MyEvents[5] не должны указывать на две одинаковые структуры, а должны указывать на одну и ту же структуру.

Перегрузка же оператора получается создаёт копию структуры. Структуры данных могут быть очень тяжелые или их может быть много, и нет надобности в их копировании, а просто нужно, чтобы в массиве адресация на структуру данных перескочила с одного индекса на другой. Что-то типа такого *MyEvents[2] = *MyEvents[1]. Тут возможно я некорректно использовал указатели, поэтому поясню так. Нужно взять адрес по MyEvents[2] и изменить на адрес по MyEvents[1].

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

Распределенные вычисления в сети MQL5 Cloud Network
Распределенные вычисления в сети MQL5 Cloud Network
  • cloud.mql5.com
Большую часть времени современные компьютеры простаивают и не используют всех возможностей процессора. Мы предлагаем задействовать их с пользой. Вы можете сдавать мощности вашего компьютера другим участникам нашей сети для выполнения разнообразных...
 
Как я понял, для того чтобы реализовать такой механизм "тасовки" ссылок на структуры в массиве придется эти структуры реализовывать через классы.
Попробовал такой пример, и вроде заработало. Понимаю, что ещё нужно будет следить за удалением созданных через new объектов классов.
В объявлении переменных описал тестовый класс и динамический массив указателей (как я понимаю по сути теже ссылки) на классы:
class MyClassTest
{
        public:
        int a;
        double b;
        string c;
};

MyClassTest* arrayRefsMyClassTest[];
И сделал такие проверки:
Print("Тест операций над массивом ссылок на классы: начало");

// создаём объекты классов и сохраняем ссылки на них в массиве ссылок.
i = 0;
while( i<5 )
{
        ArrayResize(arrayRefsMyClassTest, i+1);
        arrayRefsMyClassTest[i] = new MyClassTest();
        arrayRefsMyClassTest[i].a = i;
        arrayRefsMyClassTest[i].b = 3.14+i;
        arrayRefsMyClassTest[i].c = "testclass" + i;
        i = i + 1;
}

i = 0;
while( i<ArraySize(arrayRefsMyClassTest) ) { if( CheckPointer(arrayRefsMyClassTest[i])!=POINTER_INVALID ) Print("arrayRefsMyClassTest[" + i + "]: a = " + arrayRefsMyClassTest[i].a, ", b = " + arrayRefsMyClassTest[i].b + ", c = " + arrayRefsMyClassTest[i].c); i = i + 1; }

Print("Изменяем размер массива ссылок на классы");
ArrayResize(arrayRefsMyClassTest, ArraySize(arrayRefsMyClassTest)+2);

i = 0;
while( i<ArraySize(arrayRefsMyClassTest) ) { if( CheckPointer(arrayRefsMyClassTest[i])!=POINTER_INVALID ) Print("arrayRefsMyClassTest[" + i + "]: a = " + arrayRefsMyClassTest[i].a, ", b = " + arrayRefsMyClassTest[i].b + ", c = " + arrayRefsMyClassTest[i].c); i = i + 1; }

Print("Присваиваю последнему элементу ссылку во втором элементе");
i =  ArraySize(arrayRefsMyClassTest) - 1;
arrayRefsMyClassTest[i] = arrayRefsMyClassTest[2];

i = 0;
while( i<ArraySize(arrayRefsMyClassTest) ) { if( CheckPointer(arrayRefsMyClassTest[i])!=POINTER_INVALID ) Print("arrayRefsMyClassTest[" + i + "]: a = " + arrayRefsMyClassTest[i].a, ", b = " + arrayRefsMyClassTest[i].b + ", c = " + arrayRefsMyClassTest[i].c); i = i + 1; }

Print("Присваиваю 2 элементу ссылку в 5 элементе");
arrayRefsMyClassTest[1] = arrayRefsMyClassTest[5];

i = 0;
while( i<ArraySize(arrayRefsMyClassTest) ) { if( CheckPointer(arrayRefsMyClassTest[i])!=POINTER_INVALID ) Print("arrayRefsMyClassTest[" + i + "]: a = " + arrayRefsMyClassTest[i].a, ", b = " + arrayRefsMyClassTest[i].b + ", c = " + arrayRefsMyClassTest[i].c); i = i + 1; }

Print("\nТест операций над массивом ссылок на классы: конец");
В логе получил такие результаты:
Тест операций над массивом ссылок на классы: начало
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[0]: a = 0, b = 3.14, c = testclass0
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[1]: a = 1, b = 4.14, c = testclass1
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[2]: a = 2, b = 5.14, c = testclass2
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[3]: a = 3, b = 6.14, c = testclass3
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[4]: a = 4, b = 7.14, c = testclass4
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: Изменяем размер массива ссылок на классы
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[0]: a = 0, b = 3.14, c = testclass0
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[1]: a = 1, b = 4.14, c = testclass1
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[2]: a = 2, b = 5.14, c = testclass2
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[3]: a = 3, b = 6.14, c = testclass3
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[4]: a = 4, b = 7.14, c = testclass4
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: Присваиваю последнему элементу ссылку во втором элементе
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[0]: a = 0, b = 3.14, c = testclass0
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[1]: a = 1, b = 4.14, c = testclass1
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[2]: a = 2, b = 5.14, c = testclass2
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[3]: a = 3, b = 6.14, c = testclass3
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[4]: a = 4, b = 7.14, c = testclass4
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[6]: a = 2, b = 5.14, c = testclass2
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: Присваиваю 2 элементу ссылку в 5 элементе
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[0]: a = 0, b = 3.14, c = testclass0
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[1]: a = 4, b = 7.14, c = testclass4
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[2]: a = 2, b = 5.14, c = testclass2
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[3]: a = 3, b = 6.14, c = testclass3
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[4]: a = 4, b = 7.14, c = testclass4
0       21:59:14.658    2018.02.01 00:00:00  Tester3 EURUSD,M5: arrayRefsMyClassTest[6]: a = 2, b = 5.14, c = testclass2
Тест операций над массивом ссылок на классы: конец
Вроде заработало как надо. Лишние копии данных в данном случае как я понял не создаются. Если я не прав поправте меня пожайлуста. Может есть какие замечания или уточнения?
 
как в MQL5(или с помощью WinAPI) развернуть график на весь экран???
 
GitSM:
Как я понял, для того чтобы реализовать такой механизм "тасовки" ссылок на структуры в массиве придется эти структуры реализовывать через классы.

Да, к сожалению, указатели на структуры в MQL сделать нельзя. Непонятно, почему сделано такое ограничение, если с классами можно. Ведь структуры от классов отличаются не очень то и сильно.