- Вступ
- механізація бектестінга
- Торгові системи, засновані на перетинах двох мовного
- Торгові системи, засновані на перетинах двох осциляторів
- висновок
Вступ
Надійшла пропозиція від читача попередньої статті трохи механізувати сам процес бектестінга, щоб за один загальний візит можна було отримати результати всіх оптимізацій одночасно. Та й весь час пересувати період тестування в бектестінга теж не так щоб і дуже зручно, краще це якось зробити в автопілотні режимі. Сама ідея просто чудова - благо можливостей для її реалізації в MQL4 більш ніж достатньо, так що з вирішення цього завдання я і почну цю статтю.
механізація бектестінга
Для вирішення цього завдання слід:
1. Вписати під шапкою будь-якого, що цікавить вас експерта рядок такого змісту:
#include <IsBackTestingTime.mqh>За допомогою цієї директиви ми включаємо в код експерта функцію IsBackTestingTime (). Цілком природно слід не забути помістити файл IsBackTestingTime.mqh в папку INCLUDE. Ця функція:
bool IsBackTestingTime () {}призначена для визначення часу, протягом якого відбувається бектестерная оптимізація або бектестінга. У ці періоди часу ця функція завжди повертає true, в решту часу ця функція повертає false. Крім цієї функції в код експерта цією директивою додаються зовнішні експертні змінні:
extern datetime Start_Time = D'2007.01.01 '; extern int Opt_Period = 3; extern int Test_Period = 2; extern int Period_Shift = 1; extern int Opt_Number = 0;Я сподіваюся, що зміст цих змінних буде абсолютно зрозумілий всім, хто читав мою попередню статтю , І пояснювати їх зміст вдруге дещо зайве!
2. У блок стартовою функції перед кодом експерта необхідно помістити найпростіший універсальний код звернення до функції IsBackTestingTime (), що обмежує роботу експерта певними часовими рамками, в залежності від номера бектестерной оптимізації.
if (! IsBackTestingTime ()) return (0);
Схематично це буде виглядати наступним чином:
#property copyright "Copyright © 2008, Nikolay Kositsin" #property link "[email protected]" #include <IsBackTestingTime.mqh> int init () {return (0); } Int start () {if (! IsBackTestingTime ()) return (0); return (0); }Кому интерсно рішення такого завдання на прикладі готового експерта, можуть подивитися код експерта Exp_5_1.mq4, що є модифікованим для бектестінга експертом Exp_5.mq4 з попередньої статті . За великим рахунком якоїсь значної різниці в оптимізації подібного експерта в порівнянні зі звичайним експертом немає. Хіба що, на мій погляд, не варто оптимізувати бектестерние змінні, за винятком змінної Opt_Number, хоча хтозна, тут у кожного свій підхід повинен бути.
Найголовніше не забувати, що після оптимізації при тестуванні ми отримуємо результати вже не всередині періоду оптимізації, а після нього, за правою границею! І все-таки робити все бектестерние оптимізації за один захід за допомогою генетичного алгоритму не зовсім зручніше, набагато цікавіше робити більш поглиблене дослідження кожної бектестерной оптимізації окремо без оптимізації вхідної змінної Opt_Number.
Але навіть в цьому випадку подібний підхід дуже сильно прискорює розуміння поведінки експерта. Ну і при подібному заході слід пам'ятати, що значення зовнішньої змінної Opt_Number може змінюватися від нуля і до деякого максимального значення, яке можна визначити наступним чином: від загальної періоду, на якому проводяться всі бектестерние оптимізації взятого в місцях, віднімається період бектестерной оптимізації в місцях ( Opt_Period) і віднімається період бектестінга (Test_Period). До отриманої величини додати одиницю. Отриманий результат і буде максимумом для змінної Opt_Number, в разі, якщо Period_Shift дорівнює одиниці.
Торгові системи, засновані на перетинах двох мовного
Цей варіант торгових систем досить поширений, і алгоритм, що лежить в їх основі давно слід було розглянути детальніше. Для довгих позицій алгоритм входу в ринок буде виглядати наступним чином:
Для коротких позицій алгоритм входу в ринок аналогічно буде таким:
В якості індикаторів можуть використовуватися два однакових мувинга з різними значеннями параметрів, що визначають усереднення в індикаторах. Передбачається, що параметр, що визначає усереднення у мувинга MovA має завжди менше значення, ніж цей же параметр у мувинга MovB. Таким чином мовного MovA виявляється у цій торговельній системі швидким мовного, а мовного MovB повільним. Ось варіант реалізації даної торгової системи на двох JMA мовного:
#property copyright "Copyright © 2007, Nikolay Kositsin" #property link "[email protected]" extern bool Test_Up = true; extern int Timeframe_Up = 240; extern double Money_Management_Up = 0.1; extern int LengthA_Up = 4; extern int PhaseA_Up = 100; extern int IPCA_Up = 0; extern int LengthB_Up = 4; extern int PhaseB_Up = 100; extern int IPCB_Up = 0; extern int STOPLOSS_Up = 50; extern int TAKEPROFIT_Up = 100; extern bool ClosePos_Up = true; extern bool Test_Dn = true; extern int Timeframe_Dn = 240; extern double Money_Management_Dn = 0.1; extern int LengthA_Dn = 4; extern int PhaseA_Dn = 100; extern int IPCA_Dn = 0; extern int LengthB_Dn = 4; extern int PhaseB_Dn = 100; extern int IPCB_Dn = 0; extern int STOPLOSS_Dn = 50; extern int TAKEPROFIT_Dn = 100; extern bool ClosePos_Dn = true; int MinBar_Up, MinBar_Dn; #include <Lite_EXPERT1.mqh> int init () {if (Timeframe_Up! = 1) if (Timeframe_Up! = 5) if (Timeframe_Up! = 15) if (Timeframe_Up! = 30) if (Timeframe_Up! = 60) if (Timeframe_Up ! = 240) if (Timeframe_Up! = 1440) Print (StringConcatenate ( "Параметр Timeframe_Up не може", "бути рівним", Timeframe_Up, "!!!")); if (Timeframe_Dn! = 1) if (Timeframe_Dn! = 5) if (Timeframe_Dn! = 15) if (Timeframe_Dn! = 30) if (Timeframe_Dn! = 60) if (Timeframe_Dn! = 240) if (Timeframe_Dn! = 1440) Print (StringConcatenate ( "Параметр Timeframe_Dn не може", "бути рівним", Timeframe_Dn, "!!!")); MinBar_Up = 4 + 30; MinBar_Dn = 4 + 30; return (0); } Int deinit () {return (0); } Int start () {int bar; double MovA [2], MovB [2]; static int LastBars_Up, LastBars_Dn; static bool BUY_Sign, BUY_Stop, SELL_Sign, SELL_Stop; if (Test_Up) {int IBARS_Up = iBars (NULL, Timeframe_Up); if (IBARS_Up> = MinBar_Up) {if (LastBars_Up! = IBARS_Up) {BUY_Sign = false; BUY_Stop = false; LastBars_Up = IBARS_Up; for (bar = 1; bar <3; bar ++) MovA [bar - 1] = (NULL, Timeframe_Up, "JJMA", LengthA_Up, PhaseA_Up, 0, IPCA_Up, 0, bar); for (bar = 1; bar <3; bar ++) MovB [bar - 1] = (NULL, Timeframe_Up, "JJMA", LengthA_Up + LengthB_Up, PhaseB_Up, 0, IPCB_Up, 0, bar); if (MovA [1] <MovB [1]) if (MovA [0]> MovB [0]) BUY_Sign = true; if (MovA [0]> MovB [0]) BUY_Stop = true; } If (! OpenBuyOrder1 (BUY_Sign, 1, Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up)) return (- 1); if (ClosePos_Up) if (! CloseOrder1 (BUY_Stop, 1)) return (- 1); }} If (Test_Dn) {int IBARS_Dn = iBars (NULL, Timeframe_Dn); if (IBARS_Dn> = MinBar_Dn) {if (LastBars_Dn! = IBARS_Dn) {SELL_Sign = false; SELL_Stop = false; LastBars_Dn = IBARS_Dn; for (bar = 1; bar <3; bar ++) MovA [bar - 1] = (NULL, Timeframe_Dn, "JJMA", LengthA_Dn, PhaseA_Dn, 0, IPCA_Dn, 0, bar); for (bar = 1; bar <3; bar ++) MovB [bar - 1] = (NULL, Timeframe_Dn, "JJMA", LengthA_Dn + LengthB_Dn, PhaseB_Dn, 0, IPCB_Dn, 0, bar); if (MovA [1]> MovB [1]) if (MovA [0] <MovB [0]) SELL_Sign = true; if (MovA [0] <MovB [0]) SELL_Stop = true; } If (! OpenSellOrder1 (SELL_Sign, 2, Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn)) return (- 1); if (ClosePos_Dn) if (! CloseOrder1 (SELL_Stop, 2)) return (- 1); }} Return (0); }Торгові системи, засновані на перетинах двох осциляторів
Абсолютно аналогічно подібна торгова система може використовуватися не тільки з мовного, а й з осцилляторами, але в цій ситуації, як я вже писав в попередній статті , Виявляється при отриманні сигналів набагато логічніше не відразу входити в ринок, а ставити відкладені ордери. В якості самого наочного прикладу можна використовувати діаграму MACD.
Для виставлення відкладених ордерів BuyLimit алгоритм буде виглядати наступним чином:
Аналогічний алгоритм для ордерів типу SellLimit отримаємо в наступному вигляді:
Код цього експерта в чому аналогічний коду попереднього експерта:
#property copyright "Copyright © 2007, Nikolay Kositsin" #property link "[email protected]" extern bool Test_Up = true; extern int Timeframe_Up = 240; extern double Money_Management_Up = 0.1; extern int FST_period_Up = 12; extern int SLO_period_Up = 22; extern int SIGN_period_Up = 8; extern int Price_Up = 0; extern int STOPLOSS_Up = 50; extern int TAKEPROFIT_Up = 100; extern int PriceLevel_Up = 40; extern bool ClosePos_Up = true; extern bool Test_Dn = true; extern int Timeframe_Dn = 240; extern double Money_Management_Dn = 0.1; extern int FST_period_Dn = 12; extern int SLO_period_Dn = 22; extern int SIGN_period_Dn = 8; extern int Price_Dn = 0; extern int STOPLOSS_Dn = 50; extern int TAKEPROFIT_Dn = 100; extern int PriceLevel_Dn = 40; extern bool ClosePos_Dn = true; int MinBar_Up, MinBar_Dn; #include <Lite_EXPERT1.mqh> int init () {if (Timeframe_Up! = 1) if (Timeframe_Up! = 5) if (Timeframe_Up! = 15) if (Timeframe_Up! = 30) if (Timeframe_Up! = 60) if (Timeframe_Up ! = 240) if (Timeframe_Up! = 1440) Print (StringConcatenate ( "Параметр Timeframe_Up не може", "бути рівним", Timeframe_Up, "!!!")); if (Timeframe_Dn! = 1) if (Timeframe_Dn! = 5) if (Timeframe_Dn! = 15) if (Timeframe_Dn! = 30) if (Timeframe_Dn! = 60) if (Timeframe_Dn! = 240) if (Timeframe_Dn! = 1440) Print (StringConcatenate ( "Параметр Timeframe_Dn не може", "бути рівним", Timeframe_Dn, "!!!")); MinBar_Up = 4 + FST_period_Up + SLO_period_Up + SIGN_period_Up; MinBar_Dn = 4 + FST_period_Dn + SLO_period_Dn + SIGN_period_Dn; return (0); } Int deinit () {return (0); } Int start () {int bar; double MovA [2], MovB [2]; static int LastBars_Up, LastBars_Dn; static datetime StopTime_Up, StopTime_Dn; static bool BUY_Sign, BUY_Stop, SELL_Sign, SELL_Stop; if (Test_Up) {int IBARS_Up = iBars (NULL, Timeframe_Up); if (IBARS_Up> = MinBar_Up) {if (LastBars_Up! = IBARS_Up) {BUY_Sign = false; BUY_Stop = false; LastBars_Up = IBARS_Up; StopTime_Up = iTime (NULL, Timeframe_Up, 0) + 60 * Timeframe_Up; for (bar = 1; bar <3; bar ++) MovA [bar - 1] = (NULL, Timeframe_Up, FST_period_Up, FST_period_Up + SLO_period_Up, SIGN_period_Up, Price_Up, 0, bar); for (bar = 1; bar <3; bar ++) MovB [bar - 1] = (NULL, Timeframe_Up, FST_period_Up, FST_period_Up + SLO_period_Up, SIGN_period_Up, Price_Up, 1, bar); if (MovA [1] <MovB [1]) if (MovA [0]> MovB [0]) BUY_Sign = true; if (MovA [0]> MovB [0]) BUY_Stop = true; } If (! OpenBuyLimitOrder1 (BUY_Sign, 1, Money_Management_Up, STOPLOSS_Up, TAKEPROFIT_Up, PriceLevel_Up, StopTime_Up)) return (- 1); if (ClosePos_Up) if (! CloseOrder1 (BUY_Stop, 1)) return (- 1); }} If (Test_Dn) {int IBARS_Dn = iBars (NULL, Timeframe_Dn); if (IBARS_Dn> = MinBar_Dn) {if (LastBars_Dn! = IBARS_Dn) {SELL_Sign = false; SELL_Stop = false; LastBars_Dn = IBARS_Dn; StopTime_Dn = iTime (NULL, Timeframe_Dn, 0) + 60 * Timeframe_Dn; for (bar = 1; bar <3; bar ++) MovA [bar - 1] = (NULL, Timeframe_Dn, FST_period_Dn, FST_period_Dn + SLO_period_Dn, SIGN_period_Dn, Price_Dn, 0, bar); for (bar = 1; bar <3; bar ++) MovB [bar - 1] = (NULL, Timeframe_Dn, FST_period_Dn, FST_period_Dn + SLO_period_Dn, SIGN_period_Dn, Price_Dn, 1, bar); if (MovA [1]> MovB [1]) if (MovA [0] <MovB [0]) SELL_Sign = true; if (MovA [0] <MovB [0]) SELL_Stop = true; } If (! OpenSellLimitOrder1 (SELL_Sign, 2, Money_Management_Dn, STOPLOSS_Dn, TAKEPROFIT_Dn, PriceLevel_Dn, StopTime_Dn)) return (- 1); if (ClosePos_Dn) if (! CloseOrder1 (SELL_Stop, 2)) return (- 1); }} Return (0); }висновок
Чергова стаття підходить до свого кінця. Чергова торгова система була абсолютно без проблем реалізована в експертів на абсолютно різних варіантах індикаторів. Я сподіваюся, що дана стаття виявиться корисною початківцям експертопісателям для подальшого розвитку навичок перетворення спочатку правильно формалізованих алгоритмів, що лежать в основі торгових систем, в готовий і абсолютно робочий код ваших експертів.