Программирование на MQL 4: Торговые системы. Часть 3.
|

Программирование на MQL 4: Торговые системы. Часть 3.

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


   Итак, за основу МТС выберем торговую систему на индикаторе RSI. Сразу оговоримся, что рассматриваемая система является чисто иллюстративной и не планируется для каких-либо практических на финансовых рынках. Более того, значения параметров этой системы взяты произвольно и не имеют ничего общего с параметрами, реально требующимися в данной ситуации.


   Приведём для начала словесное описание системы:


   Одна одновременно открытая позиция.


   Индикатор RSI. Период индикатора будет задан параметром советника.


   1. Правила открытия позиции: сигналом на открытие короткой позиции будем считать пересечение кривой RSI сверху вниз уровней 80% и 70% подряд. То есть, если перед пересечением уровня 70% нет пересечения 80% уровня, то такое поведение цены не следует принимать во внимание; сигналом на открытие длинной позиции будем считать пересечение кривой RSI снизу вверх двух уровней 20% и 30% подряд. То есть, если перед пересечением уровня 30% нет пересечения 20% уровня, то не принимать во внимание такое поведение цены.


   2. Правила закрытия позиции: сигналом на закрытие длинной позиции будем считать пересечение снизу вверх уровня 80%; сигналом на закрытие короткой позиции будем считать пересечение сверху вниз уровня 20%. Кроме этих двух сигналов на закрытие позиции, ордера будут закрываться по stop-loss’у, который будет рассчитан, как процент от текущей цены. Процент будет задан параметром советника.


   3. Размер позиции будет рассчитываться, как процент от депозита. Процент будет задан параметром советника.


   Далее следуем в соответствии со сценарием, описанным в предыдущих статьях, посвящённых Торговым системам.


   С помощью мастера написания советников, создаём остов советника RSI-advisor. Не забудьте на втором этапе выполнения мастера написания советников добавить параметры: nRsiPeriod типа int и начальным значением 8; fStopLoss типа double и начальным значением 1,5 и fLots типа double и начальным значением 0,10.


   Получив остов индикатора, начинаем наполнять его логикой.


   Никаких особенных ограничений на входные параметры мы не накладываем, и поэтому функция советника init() останется без изменений.


   Все правила, которые мы указали в словесном описании нашей торговой системы будут проверяться и обрабатываться в функции советника start(). Далее приведён исходный код индикатора, в котором все шаги подробно прокомментированы.


//+——————————————————————+
//| RSI-advisor.mq4 |
//| Copyright © 2004, Horn |
//| alexander@indus.ru |
//+——————————————————————+
#define copyright “Copyright © 2004, Horn”
#define link “alexander@indus.ru
int g_nRsiPeriod;
double g_fStopLoss;
double g_fLots;
int init(int nRsiPeriod=8,double fStopLoss=0.5,double fLots=.10)
{
g_nRsiPeriod=nRsiPeriod;
g_fStopLoss=fStopLoss;
g_fLots=fLots;
return(0);
}
int deinit()
{
return(0);
}
int start()
{
// Если эта функция была вызвана MetaTrader’ом,
// значит либо изменилась цена, либо советник
// запущен впервые.
int nShift = 0;
int nOrders = 0;
double fCurrentRSI = 0;
double fPreviousRSI = 0;
double fShiftRSI = 0;
// Не истёк ли 10-ти секундный лимит?
if(CurTime() – LastAttemptTime() < 10) return(0);
// Получаем значения индикатора RSI на текущем и предыдущем барах
fCurrentRSI = iRSI(g_nRsiPeriod,0,PRICE_CLOSE,MODE_FIRST,0);
fPreviousRSI = iRSI(g_nRsiPeriod,0,PRICE_CLOSE,MODE_FIRST,1);
// Не превышено ли количество открытых ордеров?
nOrders=OrderTotal();
if((nOrders < 1)&&(AccountFreeMargin() >= 1000*g_fLots*1.5)) {
// Если открытых позиций нет, и на счету достаточно свободных
// средств, то мы проверяем значения индикаторов
// для проверки сигнала на открытие новой позиции.
// Проверим, опустилось ли на текущем баре значение RSI
// в коридор от 30% до 70%.
if((fCurrentRSI) < 70 || (fCurrentRSI) > 30) {
// Проверим, было ли значение RSI на предыдущем баре больше
// 70% линии
if(fPreviousRSI > 70) {
// Появился шанс открыть короткую позицию!
// Осталось только проверить, спустилось ли значение
// RSI из зоны перекупленности 80%-100%
for(nShift = 2; nShift < Bars; nShift++ ){
fShiftRSI = iRSI(g_nRsiPeriod,0,PRICE_CLOSE,MODE_FIRST,nShift);
if(fShiftRSI >= 80) {
// Открываем короткую позицию и выходим
OrderSet(OP_SELL,g_fLots,Bid,3,Ask+(Ask*g_fStopLoss/100),0,Blue);
return(0);
}else if(fShiftRSI < 70) {
// Значение RSI “пришло” не из зоны перекупленности 80%-100%,
// а, поднявшись из коридора 30%-70%, “болталось”
// в коридоре 70%-80%. Такое пересечение RSI и
// уровня 70% мы не рассматриваем, как сигнал и заканчиваем
// перебирать предыдущие бары.
break;
}
}
} else
// Проверим, было ли значение RSI на предыдущем баре меньше
// 30% линии
if(fPreviousRSI <= 30) {
// Появился шанс открыть длинную позицию!
// Осталось только проверить, поднялось ли значение
// RSI из зоны перепроданности 0%-20%
for(nShift = 2; nShift < Bars; nShift++ ){
fShiftRSI = iRSI(g_nRsiPeriod,0,PRICE_CLOSE,MODE_FIRST,nShift);
if(fShiftRSI <= 20) {
// Открываем длинную позицию и выходим
OrderSet(OP_BUY,g_fLots,Ask,3,Bid-(Bid*g_fStopLoss/100),0,Red);
return(0);
}else if(fShiftRSI > 30) {
// Значение RSI “пришло” не из зоны перепроданности 0%-20%
// а, опустившись из коридора 30%-70%, “болталось”
// в коридоре 20%-30%. Такое пересечение RSI и
// уровня 30% мы не рассматриваем, как сигнал и заканчиваем
// перебирать предыдущие бары.
break;
}
}
}
}
}
// Если нет возможности открыть новую позицию,
// то следует проверить, не пора ли закрыть уже открытую позицию.
for(nShift = 0; nShift < nOrders; nShift++) {
int nType=OrderGet(nShift,VAL_TYPE);
if(nType==OP_BUY) {
if(fCurrentRSI >= 80) {
// Покупая, мы попали в зону перекупленности,
// следовательно, пора закрываться
OrderClose(OrderGet(nShift,VAL_TICKET),OrderGet(nShift,VAL_LOTS),
Bid,3,Violet);
return(0);
}
} else if(nType==OP_SELL) {
if(fCurrentRSI <= 20) {
// Продавая, мы попали в зону перепроданности,
// следовательно, пора закрываться
OrderClose(OrderGet(nShift,VAL_TICKET),OrderGet(nShift,VAL_LOTS),
Ask,3,Magenta);
return(0);
}
}
}
return(0);
}


   Достаточно простые условия торговли описанной МТС дают малое количество входных параметров, что всегда оценивается, как один из плюсов торговой системы. Когда появится возможность протестировать советника, нам нужно будет подобрать оптимальный период индикатора, зависящий от рассматриваемого временного периода, размер stop-loss’а, зависящий от волатильности валюты и размер лота. Размер лота следовало бы выбирать по правилам применяемого moneymanagement’а. В таком случае, можно было бы написать отдельную функцию, которая, учитывая эти правила, автоматически подсчитывала бы размер следующей сделки. Используемый способ предложен только для простоты реализации.


   Хотелось бы отметить, что финальная редакция языка MQL 4 позволит обращаться к значениям исторических данных и получать значения индикаторов разных временных периодов. В текущем варианте язык MQL 4 реализует эту возможность посредством двух функций работы с массивами. Функции ArrayCopyRates() и ArrayCopySeries() имеют параметры symbol_name и period, через которые можно указать символ и временной период исторических данных, запрашиваемых на копирование.


Александр Иванов
для Forex Magazine
fxtrade@tomsk.ru