Совместное использование программ
Ранее упоминалось, что, в соответствии с правилами MQL4, применение торговых функций
в пользовательских индикаторах не допускается, поэтому для автоматической торговли
необходимо использовать эксперт или скрипт. Однако, ресурсосберегающая технология,
принятая для расчётов в индикаторах (см. Создание пользовательских индикаторов), оказывается востребованной при создании
торгующих программ. В значительной части случаев
в пользовательских индикаторах можно эффективно рассчитать значения элементов индикаторных
массивов, необходимые для формирования в эксперте торговых критериев и принятия
торговых решений.
Расчёты, выполняемые в пользовательских индикаторах, технически возможно выполнять
и в экспертах, однако это может привести к дублированию расчётов в разных прикладных
программах и неоправданному расходованию ресурсов, а в некоторых случаях (при выполнении
длительных энергоёмких вычислений) - к запаздыванию торговых решений. В тех случаях,
когда в эксперте или скрипте возникает потребность в использовании результатов вычислений, выполненных
в пользовательском индикаторе, можно использовать функцию iCustom().
Функция iCustom()
double iCustom(string symbol, int timeframe, string name, ..., int mode, int shift)
Расчет указанного пользовательского индикатора. Пользовательский индикатор должен
быть скомпилирован (файл с расширением EX4) и находиться в директории Каталог_терминала\experts\indicators.
Параметры:
symbol - символьное имя инструмента, на данных которого будет вычисляться индикатор. NULL
означает текущий символ.
timeframe - период. Может быть одним из периодов графика. 0 означает период текущего графика.
name - имя пользовательского индикатора.
... - Список параметров (при необходимости). Передаваемые параметры должны соответствовать
порядку объявления и типу внешних (extern) переменных пользовательского индикатора.
mode - Индекс линии индикатора. Может быть от 0 до 7 и должен соответствовать индексу,
используемому одной из функций SetIndexBuffer.
shift - Индекс получаемого значения из индикаторного буфера (сдвиг относительно текущего
бара на указанное количество периодов назад).
Рассмотрим, как практически может быть использована функция iCustom(), для этого
решим следующую задачу:
|
Задача 30. Торговая стратегия построена на данных пользовательского индикатора
rocseparate.mq4. Если линия скорости изменения цены на текущем таймфрейме (оранжевая) пересекает
сглаженную среднюю линию скорости (красная жирная) ниже некоторого заданного уровня снизу
вверх, то считать значимым торговый критерий на покупку (открыть Buy и закрыть
Sell). При зеркальных условиях считать значимым критерий на продажу. Представить
код эксперта, реализующего эту стратегию. |
Принцип построения пользовательского индикатора
rocseparate.mq4 подробно рассмотрен
в разделе
Пользовательский индикатор ROC. На Рис. 131 показаны две точки, в которых линия скорости изменения цены на текущем
таймфрейме (М15) пересекается со средней сглаженной линией скорости изменения цены.
В точке А оранжевая линия пересекает красную снизу вверх, причём место пересечения
линий находится ниже уровня -0.001. В точке В оранжевая пересекает красную сверху
вниз, причём точка пересечения находится выше уровня 0.001. Факт пересечения указанных
линий должен быть вычислен в эксперте и расцениваться как сигнал на покупку (точка
А - закрыть Sell и открыть Buy) или продажу (точка В - закрыть Buy и открыть Sell).
Рис. 131. Пересечения линий пользовательского индикатора рассматривается как торговый
критерий.
При решении подобных задач можно использовать готовый эксперт, изменив в нём порядок
расчёта торговых критериев. В данном случае можно взять за основу эксперт
tradingexpert.mq4, представленный в
разделе Простой эксперт. Эксперт shared.mq4,
вычисляющий торговые критерии на основе пользовательского индикатора, будет выглядеть так:
#property copyright "Copyright © Book, 2007"
#property link "http://AutoGraf.dp.ua"
extern double StopLoss =100;
extern double TakeProfit=35;
extern double Lots =0.1;
extern double Prots =0.07;
extern int Period_MA_1 =56;
extern int Bars_V =34;
extern int Aver_Bars =0;
extern double Level =0.001;
bool Work=true;
string Symb;
int start()
{
int
Total,
Tip=-1,
Ticket;
double
MA_1_t,
MA_2_t,
Lot,
Lts,
Min_Lot,
Step,
Free,
One_Lot,
Price,
SL,
TP;
bool
Ans =false,
Cls_B=false,
Cls_S=false,
Opn_B=false,
Opn_S=false;
if(Bars < Period_MA_1)
{
Alert("Недостаточно баров в окне. Эксперт не работает.");
return;
}
if(Work==false)
{
Alert("Критическая ошибка. Эксперт не работает.");
return;
}
Symb=Symbol();
Total=0;
for(int i=1; i<=OrdersTotal(); i++)
{
if (OrderSelect(i-1,SELECT_BY_POS)==true)
{
if (OrderSymbol()!=Symb)continue;
if (OrderType()>1)
{
Alert("Обнаружен отложенный ордер. Эксперт не работает.");
return;
}
Total++;
if (Total>1)
{
Alert("Несколько рыночных ордеров. Эксперт не работает.");
return;
}
Ticket=OrderTicket();
Tip =OrderType();
Price =OrderOpenPrice();
SL =OrderStopLoss();
TP =OrderTakeProfit();
Lot =OrderLots();
}
}
int H= 1000;
int P= Period_MA_1;
int B= Bars_V;
int A= Aver_Bars;
double L_1=iCustom(NULL,0,"rocseparate",H,P,B,A,1,0);
double L_5=iCustom(NULL,0,"rocseparate",H,P,B,A,5,0);
if (L_5<=-Level && L_1>L_5)
{
Opn_B=true;
Cls_S=true;
}
if (L_5>=Level && L_1<L_5)
{
Opn_S=true;
Cls_B=true;
}
while(true)
{
if (Tip==0 && Cls_B==true)
{
Alert("Попытка закрыть Buy ",Ticket,". Ожидание ответа..");
RefreshRates();
Ans=OrderClose(Ticket,Lot,Bid,2);
if (Ans==true)
{
Alert ("Закрыт ордер Buy ",Ticket);
break;
}
if (Fun_Error(GetLastError())==1)
continue;
return;
}
if (Tip==1 && Cls_S==true)
{
Alert("Попытка закрыть Sell ",Ticket,". Ожидание ответа..");
RefreshRates();
Ans=OrderClose(Ticket,Lot,Ask,2);
if (Ans==true)
{
Alert ("Закрыт ордер Sell ",Ticket);
break;
}
if (Fun_Error(GetLastError())==1)
continue;
return;
}
break;
}
RefreshRates();
Min_Lot=MarketInfo(Symb,MODE_MINLOT);
Free =AccountFreeMargin();
One_Lot=MarketInfo(Symb,MODE_MARGINREQUIRED);
Step =MarketInfo(Symb,MODE_LOTSTEP);
if (Lots > 0)
Lts =Lots;
else
Lts=MathFloor(Free*ProtsOne_LotStep)*Step;
if(Lts < Min_Lot) Lts=Min_Lot;
if (Lts*One_Lot > Free)
{
Alert(" Не хватает денег на ", Lts," лотов");
return;
}
while(true)
{
if (Total==0 && Opn_B==true)
{
RefreshRates();
SL=Bid - New_Stop(StopLoss)*Point;
TP=Bid + New_Stop(TakeProfit)*Point;
Alert("Попытка открыть Buy. Ожидание ответа..");
Ticket=OrderSend(Symb,OP_BUY,Lts,Ask,2,SL,TP);
if (Ticket > 0)
{
Alert ("Открыт ордер Buy ",Ticket);
return;
}
if (Fun_Error(GetLastError())==1)
continue;
return;
}
if (Total==0 && Opn_S==true)
{
RefreshRates();
SL=Ask + New_Stop(StopLoss)*Point;
TP=Ask - New_Stop(TakeProfit)*Point;
Alert("Попытка открыть Sell. Ожидание ответа..");
Ticket=OrderSend(Symb,OP_SELL,Lts,Bid,2,SL,TP);
if (Ticket > 0)
{
Alert ("Открыт ордер Sell ",Ticket);
return;
}
if (Fun_Error(GetLastError())==1)
continue;
return;
}
break;
}
return;
}
int Fun_Error(int Error)
{
switch(Error)
{
case 4: Alert("Торговый сервер занят. Пробуем ещё раз..");
Sleep(3000);
return(1);
case 135:Alert("Цена изменилась. Пробуем ещё раз..");
RefreshRates();
return(1);
case 136:Alert("Нет цен. Ждём новый тик..");
while(RefreshRates()==false)
Sleep(1);
return(1);
case 137:Alert("Брокер занят. Пробуем ещё раз..");
Sleep(3000);
return(1);
case 146:Alert("Подсистема торговли занята. Пробуем ещё..");
Sleep(500);
return(1);
case 2: Alert("Общая ошибка.");
return(0);
case 5: Alert("Старая версия терминала.");
Work=false;
return(0);
case 64: Alert("Счет заблокирован.");
Work=false;
return(0);
case 133:Alert("Торговля запрещена.");
return(0);
case 134:Alert("Недостаточно денег для совершения операции.");
return(0);
default: Alert("Возникла ошибка ",Error);
return(0);
}
}
int New_Stop(int Parametr)
{
int Min_Dist=MarketInfo(Symb,MODE_STOPLEVEL);
if (Parametr<Min_Dist)
{
Parametr=Min_Dist;
Alert("Увеличена дистанция стоп-приказа.");
}
return(Parametr);
}
Рассмотрим, какие преобразования внесены в исходный код (tradingexpert.mq4). Значительная часть кода эксперта, взятого за основу, не изменилась. Изменения
внесены в два блока - блок 1-2 и блок 5-6.
В блоке 5-6 рассчитываются торговые критерии. В представленном
эксперте торговая стратегия построена на основе всего двух торговых критериев -
критерия открытия Buy и критерия открытия Sell. Принятая в эксперте стратегия предусматривает
возможность одновременного присутствия в торговле только одного рыночного ордера,
отложенные ордера не допускаются. Стратегия предполагает также закрытие противоположного
ордера при срабатывании критерия открытия; например, если значимым является критерий
для открытия Buy, то это также означает, что необходимо закрыть Sell.
Для того, чтобы в эксперте shared.mq4 использовать результаты вычислений,
выполненных в пользовательском индикаторе rocseparate.mq4, необходимо исполнить
функцию iCustom():
double L_1 = iCustom(NULL,0,"rocseparate",H,P,B,A,1,0);
double L_5 = iCustom(NULL,0,"rocseparate",H,P,B,A,5,0);
В данном случае формальные параметры, указанные в вызове функции iCustom(), означают
следующее:
NULL - расчёты в индикаторе осуществляются на основе данных по текущему финансовому
инструменту; в данном случае эксперт прикреплён в оно EURUSD, значит, будут использованы
данные по EURUSD (см. Рис. 131);
0 - при расчётах используются данные, соответствующие текущему таймфрейму; в данном
случае текущий таймфрейм М15, значит, будут использованы данные, соответствующие
М15;
"rocseparate" - название пользовательского индикатора, в котором будут
выполнены расчёты.
H,P,B и A - список настраиваемых параметров. В данном случае пользовательский индикатор
rocseparate.mq4 имеет настраиваемые параметры (блок 2-3 в коде rocseparate.mq4). Для того чтобы предоставить пользователю возможность настраивать значения этих
параметров из эксперта, они указаны в списке передаваемых параметров функции iCustom().
В эксперте могут быть определены значения этих параметров, не совпадающие по значению
с теми, что указаны в индикаторе, и при выполнении расчётов в индикаторе будут
использоваться именно эти переданные значения. Эти параметры означают следующее:
H - количество баров в расчётной истории;
P - период расчётной МА;
B - количество баров для расчёта скорости;
A - количество баров для сглаживания.
(подробное объяснение сущности указанных параметров см. в разделе
Пользовательский индикатор ROC).
1 (5) - индекс линии индикатора. В пользовательском индикаторе rocseparate.mq4
используется 6 индикаторных массивов. Линия скорости изменения цены на текущем таймфрейме (оранжевая) строится на основе значений индикаторного массива Line_1[],
для которого используется буфер с индексом 1. Средняя сглаженная линия скорости
строится на основе значений элементов массива Line_5[], индекс используемого буфера
5.
0 - индекс получаемого значения из индикаторного буфера (сдвиг относительно текущего
бара на указанное количество периодов назад). В данном случае используются значения
индикаторных линий на нулевом баре, поэтому указан индекс 0.
Для того, чтобы предоставить пользователю возможность вручную в эксперте изменять
настраиваемые параметры индикатора, в блоке 1а-1b (эксперта) указаны внешние переменные. В блоке 5-5а значения этих настраиваемых параметров
переприсвоены другим переменным с более короткими именами - это сделано для удобства
представления кода в блоке 5а-5b. Таким образом, пользователь может по своему усмотрению
указать в эксперте shared.mq4 параметры, при которых будут производиться
расчёты в пользовательском индикаторе rocseparate.mq4. После исполнения функция iCustom() вернёт значение, соответствующее значению заданного элемента индикаторного
массива, вычисленного в заданном индикаторе при заданных значениях настраиваемых
параметров.
Во время практической работы удобно наблюдать в окне финансового инструмента линии
индикатора, значения индикаторных массивов которого используются в эксперте (см.
Рис. 131). Вместе с тем, исполнение функции iCustom() никак не связано с наличием в окне
финансового инструмента вызываемого индикатора, а также со значениями его настраиваемых
параметров.
|
Для исполнения функции iCustom() не требуется, чтобы соответствующий технический
индикатор был прикреплён к окну финансового инструмента. Также и вызов функции
iCustom() из какой-либо прикладной программы не приводит к присоединению соответствующего
индикатора к окну финансового инструмента. Присоединение технического индикатора
к окну финансового инструмента тоже не приводит к вызову функции iCustom() в какой-либо
прикладной программе. |
Торговые критерии в эксперте (блок 5-6) вычисляются на основе значений элементов
массивов, полученных с помощью функции Custom(). Например, критерий для открытия Buy
и закрытия Sell вычисляется так:
if (L_5<=-Level && L_1>L_5)
{
Opn_B = true;
Cls_S = true;
}
Если последнее известное значение средней сглаженной линии скорости изменения цены
(L_5) меньше заданного уровня (значение настраиваемого параметра Level = 0.001)
и при этом последнее известное значение линии скорости изменения цены в текущем
таймфрейме (L_1) больше средней сглаженной линии скорости цены (L_5), то значимыми
являются критерий для открытия ордера Buy и критерий закрытия ордера Sell. Для
подтверждения значимости противоположных критериев используются зеркальные условия.
|
Принятые в данном эксперте торговые критерии используются в учебных целях и не должны
рассматриваться как руководство к действию при торговле на реальном счёте. |