В журналі публікується безліч оглядів програм-радників і їх результативності: одні більш вдалі, інші відразу розцінюються як збиткові, що теж саме по собі результат. Але результативність радника, при його ретельному розгляді, це комплексний підсумок:
1) застосовуваної торгової стратегії (алгоритм вироблення сигналів відкриття-закриття);
2) застосовуваної техніки управління капіталом (алгоритм управління розміром лотів);
3) точності відповідності програми, записаної на MQL, описами двох перших пунктів (наявність логічних помилок) і відсутність в ній непередбачених побічних ефектів.
За двома першими позиціями написано багато, а зараз я хотів би зупинитися на деяких тонких питаннях використання мови MQL , які не знайшли ніякого відображення і згадки в описах мови (наприклад, в викладеної тут: _ // docs. mql4. com / ru / документації).
Це важливо з двох причин:
? по-перше, знання поведінки конструкцій мови, не відбите в документації, запобігає виникненню мало зрозумілих побічних ефектів в програмі;
?по-друге, дозволяє писати ефективніший код , менш схильний до прихованих помилок. Для використання цих можливостей в своїх радників не потрібно якоїсь особливої кваліфікації, їх потрібно тільки назвати і знати, що таке можна використовувати. А якщо в наступному тексті якісь формулювання вам здадуться трохи ускладненими … безболісно пропускайте їх, вони зроблені тільки для повноти викладу.
Передача параметрів в функцію за посиланням (за адресою)
Ця річ прекрасно відома програмістам на будь-якому з універсальних мов програмування, наприклад, на C, а ще більше на C ++. Напишемо найпростіший радник (файл t2. Mq4 - тут і далі імена тестових прикладів в доданому архіві), і помістимо його на графік будь-якої валютної пари:
int start () {
static int nTick = 0;
Inc (nTick);
Alert («новий тик №» + nTick);
}
// -------------
void Inc (int n) {n ++;}
Результатом виконання буде безперервне повторення одного і того ж результату: «новий тик №0» … Передане в функцію значення n змінюється там, але це не робить ніякого впливу на зовнішнє оточення функції (що викликала функцію start ()) - в функцію передається копія змінної nTick, так зазвичай працює виклик функцій в MQL4. Додамо один символ (&) в опис функції Inc ():
void Inc (int & n) {n ++;}
Виконання радника радикально зміниться:
новий тик № 1
новий тик № 2
новий тик № 3 …
Значок &вказав, що в функцію потрібно передати нам не копію, а оригінал змінної nTick, і всі зміни, зроблені над цієї змінної всередині функції, будуть відображатися на значенні цієї змінної зовні функції. Така поведінка називають побічний ефект функції .
Які наслідки несе в собі цей маленький курйоз? Дуже далекосяжні. Функції в MQL вельми обмежені, вони можуть повертати лише одне значення найпростішого типу: int, string, datetime, … За рахунок побічного ефекту, функція з багатьма параметрами може внести зміни в усі з них, фактично роблячи повернення (після свого виконання) більше одного результату (або це можна розцінювати як повернення структурованих даних). Наприклад, така функція:
Передача в функцію параметром масиву по посиланню
Наступний приклад (файл t3. Mq4) близький до попереднього, але тут побічні ефекти і супутні можливості істотно більше:
extern int N = 7;int A [];
// ----------------------
int init () {
ArrayResize (A, N);
Alert («розмір масиву» + ArraySize (A));
for (int i = 0; i } // ---------------------- int start () { static nBars = 0; // щоб не вчащати, тепер на барах, а не на тиках if (nBars! = Bars) {// щоб не чекати, запускайте на M1 nBars = Bars; IncArray (A); ShowArray (A); } } // ---------------------- void IncArray (int & Array []) { int n = ArraySize (Array); for (int i = 0; i } void ShowArray (int Array []) { int n = ArraySize (Array); string Msg = «»; for (int i = 0; i Msg = Msg + Array [i]; if (i } Alert (Msg); } 2, 3, 4, 5, 6, 7, 8 3, 4, 5, 6, 7, 8, 9 4, 5, 6, 7, 8, 9, 10 … Висновки: Тепер змінам піддається окремо кожен елемент переданого масиву. Примітка: Цікаво, як зміниться поведінка програми, якщо масив у функцію IncArray () буде передаватися не по посиланню?Чи буде створюватися копія масиву для роботи з ним всередині функції (подібно до попереднього прикладу для одиничного значення)? Досягаємо цього, переписавши заголовок цієї функції ось так (всього-то): … Результат несподіваний навіть для бувалих програмістів на C або C ++! На етапі компіляції, не доходячи до виконання, ми отримаємо повідомлення про помилку виду: 'Array' - array item can not be assigned C: Program Files MetaTrader - Alpari experts t3. mq4 (22, 33) Це означає, що контроль на L-value (доступність на присвоювання) для елементів масиву робиться ще компілятором! А для одиничних (скалярних) параметрів - це не так. int A [5]; for (i = 0; i ShowArray (A); ArrayResize (A, 7); for (i = 0; i ShowArray (A); Виходить, що масиву не переразмещает повністю, а «доповнюються» до потрібної розмірності - всі раніше присвоєні значення елементів зберігаються! Але без такого трюкацтва було б, мабуть, неможливо розробникам MQL4 реалізувати уявлення тайм-серії в MT4. А тепер сам обіцяний трюк - зі зміною розмірності масиву всередині функції. Для цього тільки перепишемо одну функцію з попереднього прикладу: int n = ArraySize (Array); ArrayResize (A, n + 1); for (int i = 0; i <= n; i ++) Array [i] = i + 1; } Результат виконання (скопійовано з журналу терміналу MetaTrader 4 (// fortrader.org / forex-terminals / torgovyj-terminal-metatrader-4-skachat. html), який розгортає результати знизу-вгору): … 2011 року. 02. 10 19: 54: 00 @ t3 EURUSD, M1: alert: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 2011 року. 02. 10 19: 53: 02 @ t3 EURUSD, M1: alert: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 2011 року. 02. 10 19: 52: 08 @ t3 EURUSD, M1: alert: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 … Примітка: Ще раз повернемося до питання, розглянутого вище: як взагалі (копією або оригіналом) передається в функцію масив в MQL4? Для цього ще раз перепишемо: void IncArray (int Array []) { ArrayResize (A, n + 1); } І отримаємо досить несподіваний результат: 2011 року. 03. 07 20: 17: 02 t4 EURUSD, M1: Alert: 1, 2, 3, 4, 5, 6, 7, 0, 0, 0 2011 року. 03. 07 20: 16: 01 t4 EURUSD, M1: Alert: 1, 2, 3, 4, 5, 6, 7, 0, 0 2011 року. 03. 07 20: 15: 44 t4 EURUSD, M1: Alert: 1, 2, 3, 4, 5, 6, 7, 0 Наступний трюк може повалити в подив навіть запеклого програміста на класичних мовах програмування. Сама по собі можливість в будь-який час змінити розмір масиву - це вже сама по собі значна особливість мови MQL4:
В результаті, можна стверджувати, що масив передається в функцію завжди по посиланню, але якщо ви це не вкажете явно (&),
компіляторбуде стежити і перешкоджати спробам змінити елементи масиву.