Донецкий техникум промышленной автоматики

Експерти на основі популярних торгових систем і алхімія оптимізації торгового робота (Продовження)

  1. Вступ
  2. механізація бектестінга
  3. Торгові системи, засновані на перетинах двох мовного
  4. Торгові системи, засновані на перетинах двох осциляторів
  5. висновок

Вступ


Надійшла пропозиція від читача попередньої статті трохи механізувати сам процес бектестінга, щоб за один загальний візит можна було отримати результати всіх оптимізацій одночасно. Та й весь час пересувати період тестування в бектестінга теж не так щоб і дуже зручно, краще це якось зробити в автопілотні режимі. Сама ідея просто чудова - благо можливостей для її реалізації в 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); }

висновок

Чергова стаття підходить до свого кінця. Чергова торгова система була абсолютно без проблем реалізована в експертів на абсолютно різних варіантах індикаторів. Я сподіваюся, що дана стаття виявиться корисною початківцям експертопісателям для подальшого розвитку навичок перетворення спочатку правильно формалізованих алгоритмів, що лежать в основі торгових систем, в готовий і абсолютно робочий код ваших експертів.