Метод площадей
- Введение
- 1. Общепринятая методика оценки показателей индикатора RSI
- 2. Метод площадей
- 3. Индикатор RSIAreaIndicator_v1
- 3.1. Создаём заготовку индикатора
- 3.2. Заполнение "шапки" индикатора
- 3.3. Редактирование функции OnInit() индикатора
- 3.4. Создание вспомогательной функции индикатора
- 3.5. Создание основного рабочего кода индикатора
- 4. Советник RSIAreaExpert version 1.00
- 4.1. Редактирование "шапки" советника
- 4.2. Вспомогательная функция RSIAreaFunc
- 4.3. Проверочный код работы функции CopyBuffer
- 4.4. Продолжение редактирования вспомогательной функции
- 4.5. Функция OnTick() советника
- 5. Тестирование советника RSIAreaExpert version 1.00 на разных периодах и символах
- Заключение
- Список использованной литературы
Введение
Как правильно установить индикаторы и советники из архивов в конце статьи: архивы "Indicators.zip" и "Experts.zip" нужно разархивировать в <каталог данных>\MQL5\
Описание метода площадей было впервые опубликовано в 2004 году [1]. Метод интересен необычным взглядом на данные индикатора RSI: в нем предлагается оценивать площадь, которую осциллятор рисует выше/ниже линии 50 с момента последнего ее пересечения. С 2004 года рынки сильно изменились, был создан язык MQL5 – а значит, пришло время проверить стратегию на языке MQL5 и на современном рынке.
1. Общепринятая методика оценки показателей индикатора RSI
Обычный метод торговли по сигналам индикатора RSI – это оценка показателей индикатора на предмет перекупленности/перепроданности, поиск дивергенции между показаниями индикатора и ценой, разворот после посещения индикатором зон перекупленности/перепроданности, неудавшийся размах. Таким образом, для технического анализа осциллятора RSI применяется минимум четыре сигнала, и это усложняет систему принятия решений.
При этом мы знаем, что индикатор RSI не может находиться в зоне перекупленности (выше линии 70)/перепроданности (ниже линии 30) очень долго – он обязательно вернётся и пересечёт среднюю линию 50:
Рис. 1. Осциллятор RSI всегда возвращается из зон перекупленности/перепроданности
На рисунке 1 видно, что суммарное время нахождения осциллятора в зонах перепроданности/перекупленности, по сравнению с остальным временем, очень мало. Также после посещения зон перекупленности/перепроданности RSI пересекает среднюю линию 50. Именно знание того, что осциллятор RSI обязательно возвращается и пересекает линию 50, а также необходимость упрощения технического анализа показаний осциллятора RSI стали основой для разработки метода площадей.
2. Метод площадей
Метод площадей предлагает оценивать показания осциллятора RSI по одному показателю: площади, которая образована осциллятором выше/ниже линии 50. Эта величина и будет характеризовать степень перекупенности/перепроданности:
Рис. 2. Метод площадей — оценка площади над/под линией 50
Сигнал к открытию позиции в этом случае — величина площади над/под линией 50 с момента последнего ее пересечения индикатором RSI.
- При долгом нахождении RSI над линией 50 и после преодоления определённой величины площади (пусть это будет значение площади, равное 300) будет открыта позиция SELL:
Рис. 3. Сигнал на открытие SELL позиции, как только площадь стала равна 300
-
Соответственно, при долгом нахождении RSI под линией 50 и после преодоления определённой величины площади будет открыта позиция BUY.
Сигналом к закрытию позиции служит пересечение осциллятором RSI линии 50 с последующим образованием локального максимума/минимума и откат от него на величину 4% шкалы.
- Например, при долгом нахождении над линией 50 в какой-то момент мы имеем открытую позицию SELL. Затем значение индикатора начинает уменьшаться и достигает, допустим линии 40, после чего значение индикатора начинает увеличиваться (то есть, образуется локальный минимум). Когда значение индикатора достигнет линии 44, это и станет сигналом к закрытию позиции:
Рис. 4. Сигнал на закрытие SELL позиции после образования локального минимума и последующего отката на 4%
- Аналогичная логика возникает при долгом нахождении индикатора под линией 50, только в этом случае мы ждем образования локального максимума.
Для визуализации площади над/под линией 50 нам поможет индикатор RSIAreaIndicator.
3. Индикатор RSIAreaIndicator_v1
Индикатор RSIAreaIndicator построен на базе осциллятора RSI. Основное отличие состоит в том, что индикатор RSIAreaIndicator имеет два буфера. Один буфер имеет стиль построения DRAW_HISTOGRAM, а второй — DRAW_LINE. Значения буферов получают по формуле
Вид индикатора RSIAreaIndicator version 1.00:
Рис. 5. Индикатор RSIAreaIndicator _v1
3.1. Создаём заготовку индикатора
Созданные вами пользовательские индикаторы я рекомендую размещать в отдельной папке. В моем случае такая папка называется "MyInd". Чтобы начать писать индикатор, нужно создать его заготовку в редакторе кода MetaEditor с использованием помощника MQL5 Wizard. Первые шаги по созданию заготовки индикатора я собрал в этом видео:
Полученную заготовку вы можете просмотреть в конце статьи — индикатор сохранён под именем "RSIAreaIndicatorStep1.mq5".
3.2. Заполнение "шапки" индикатора
Следующий шаг — это добавление описания индикатора. Впоследствии его всегда можно будет увидеть в свойствах индикатора во вкладке "Общие". Весь добавленный код в статье будет выделяться цветом для визуального восприятия:
#property version "1.00" #property description "The indicator displays area RSI over/under line 50" #property indicator_separate_window
Как мы помним, индикатор RSIAreaIndicator имеет два индикаторных буфера. Кроме них, нам понадобится еще один, вспомогательный. Таким образом, всего в индикаторе будет использовано три буфера. Начнём редактирование кода с "шапки" индикатора:
#property indicator_separate_window #property indicator_buffers 3 #property indicator_plots 2 #property indicator_type1 DRAW_HISTOGRAM #property indicator_type2 DRAW_LINE #property indicator_color1 clrGray #property indicator_color2 clrGray //--- input parameters input int ExtRSIPeriod=13;
Теперь нужно объявить три массива, в которых будут храниться значения индикаторных и вспомогательного буферов:
//--- input parameters input int ExtRSIPeriod=13; //---- buffers double ExtMapBuffer1[]; double ExtMapBuffer2[]; double ExtMapBuffer3[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function |
Далее, так как наш индикатор RSIAreaIndicator рассчитывается на базе стандартного индикатора RSI и нам нужно будет получать значения индикатора, потребуется переменная, в которой будет храниться хэндл индикатора Relative Strength Index:
double ExtMapBuffer3[]; //--- variable for storing the handle of the iRSI indicator int handle; //+------------------------------------------------------------------+ //| Custom indicator initialization function |
Осталось объявить в "шапке" три служебных переменных. В переменной name будет храниться имя символа, на котором запущен индикатор, в переменной short_name — короткое имя индикатора, а в переменной bars_calculated — количество посчитанных баров в индикаторе RSI:
int handle; //--- variable for storing string name=Symbol(); //--- name of the indicator on a chart string short_name; //--- we will keep the number of values in the Relative Strength Index indicator int bars_calculated=0; //+------------------------------------------------------------------+ //| Custom indicator initialization function |
"Шапка" индикатора заполнена, теперь можно приступить к редактированию функции OnInit().
3.3. Редактирование функции OnInit() индикатора
Так как мы пишем индикатор, то нам нужно связать наши индикаторные буферы с объявленными ранее динамическими массивами типа double:
int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,ExtMapBuffer1,INDICATOR_DATA); SetIndexBuffer(1,ExtMapBuffer2,INDICATOR_DATA); SetIndexBuffer(2,ExtMapBuffer3,INDICATOR_CALCULATIONS); //--- return(INIT_SUCCEEDED);
Затем, сразу же после связывания буферов и массивов, установим индексацию элементов массива как в таймсериях (рекомендую просмотреть хороший пример справки по ArraySetAsSeries). Самый правый элемент массивов будет иметь индекс "0":
SetIndexBuffer(1,ExtMapBuffer2,INDICATOR_DATA); SetIndexBuffer(2,ExtMapBuffer3,INDICATOR_CALCULATIONS); ArraySetAsSeries(ExtMapBuffer1,true); ArraySetAsSeries(ExtMapBuffer2,true); ArraySetAsSeries(ExtMapBuffer3,true); //--- return(INIT_SUCCEEDED);
Теперь установим точность отображения — индикатор будет отображаться с двумя знаками после запятой:
ArraySetAsSeries(ExtMapBuffer3,true); //--- set accuracy IndicatorSetInteger(INDICATOR_DIGITS,2); //--- return(INIT_SUCCEEDED);
В функции OnInit() осталось ещё получить хэндл индикатора RSIndex, заполнить переменную short_name и присвоить нашему индикатору короткое имя:
ArraySetAsSeries(ExtMapBuffer2,true); ArraySetAsSeries(ExtMapBuffer3,true); //--- set accuracy IndicatorSetInteger(INDICATOR_DIGITS,2); handle=iRSI(name,0,ExtRSIPeriod,PRICE_CLOSE); //--- if the handle is not created if(handle==INVALID_HANDLE) { //--- notify about failure and output error code PrintFormat("Failed to create handle of the iRSI indicator for the symbol %s/%s, error code %d", name, EnumToString(PERIOD_CURRENT), GetLastError()); //--- the indicator is stopped early return(INIT_FAILED); } //--- show the symbol/timeframe the RSI Area Indicator is calculated for short_name=StringFormat("RSIArea(%d)",ExtRSIPeriod); IndicatorSetString(INDICATOR_SHORTNAME,short_name); //--- normal initialization of the indicator return(INIT_SUCCEEDED);
Итак "шапку" индикатора и функцию OnInit() мы заполнили. Отредактированный код Вы можете просмотреть в конце статьи — индикатор сохранён под именем "RSIAreaIndicatorStep2.mq5".
3.4. Создание вспомогательной функции индикатора
Для работы индикатора RSIAreaIndicator нужно при каждом заходе в функцию OnCalculate() получать данные индикатора RSI. Не менее важно обеспечить удобство чтения кода и разделить функционал программы. Поэтому вспомогательный код получения значений RSI и копирование этих значений в один из буферов RSIAreaIndicator вынесены в отдельную функцию FillArrayFromBuffer(). Ее мы разместим после OnCalculate(). Значения копируются при помощи функции CopyBuffer.
//--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Filling indicator buffers from the iRSI indicator | //+------------------------------------------------------------------+ bool FillArrayFromBuffer(double &rsi_buffer[], // indicator buffer of Relative Strength Index values int ind_handle, // handle of the iRSI indicator int amount // number of copied values ) { //--- reset error code ResetLastError(); //--- fill a part of the iRSIBuffer array with values from the indicator buffer that has 0 index if(CopyBuffer(ind_handle,0,0,amount,rsi_buffer)<0) { //--- output error code if copying fails PrintFormat("Failed to copy data from the iRSI indicator, error code %d",GetLastError()); //--- quit with zero result - it means that the indicator is considered as not calculated return(false); } //--- all in order return(true); } //+------------------------------------------------------------------+
3.5. Создание основного рабочего кода индикатора
Основной рабочий код (или логика) индикатора RSIAreaIndicator расположен в функции OnCalculate(). Здесь объявляется главная переменная — values_to_copy. Впоследствии переменная values_to_copy будет хранить количество значений, которое нужно копировать из индикатора RSI.
const int &spread[]) { //--- number of values copied from the iRSI indicator int values_to_copy; //--- determine the number of values calculated in the indicator int calculated=BarsCalculated(handle); if(calculated<=0) { PrintFormat("BarsCalculated() returned %d, error code %d",calculated,GetLastError()); return(0); } //--- return value of prev_calculated for next call return(rates_total); }
Расчёт значения values_to_copy:
PrintFormat("BarsCalculated() returned %d, error code %d",calculated,GetLastError()); return(0); } //--- if it is the first calculation of the indicator or if the number of values in the iRSI indicator changed //---calculate if(prev_calculated==0 || calculated!=bars_calculated || rates_total>prev_calculated+1) { //--- if the iRSIBuffer array is greater than the number of values in the iRSI indicator for symbol/period, then we don't copy everything //--- otherwise, we copy less than the size of indicator buffers if(calculated>rates_total) values_to_copy=rates_total; else values_to_copy=calculated; } else { //--- it means that the indicator is calculated not for the first time, but since the last call of OnCalculate() //--- not more than one bar is added for calculation values_to_copy=(rates_total-prev_calculated)+1; } //--- return value of prev_calculated for next call return(rates_total);
Почему переменная values_to_copy рассчитывается именно так? В MQL5 индикаторе элементы массивов (time[], open[], high[], low[], close[], tick_volume[], volume[] и spread[]), передаваемые в функцию OnCalculate(), имеют индексацию от начала массива к концу. Вот как это выглядит на примере графика:
Рис. 6. Индексация элементов массива, если массив не таймсерия
То есть в массиве, не являющемся таймсерией, самый правый элемент будет иметь максимальный индекс. Это нужно учитывать при математических вычислениях.
Теперь, когда значение переменной values_to_copy рассчитано, можно вызывать вспомогательную функцию FillArrayFromBuffer() и заполнить значениями индикаторные буферы ExtMapBuffer1[] и ExtMapBuffer2[]:
//--- for calculation not more than one bar is added values_to_copy=(rates_total-prev_calculated)+1; } //--- fill the array with values of the iRSI indicator //--- not ready if(!FillArrayFromBuffer(ExtMapBuffer3,handle,values_to_copy)) return(0); //--- for(int i=0;i<values_to_copy;i++) { ExtMapBuffer1[i]=ExtMapBuffer2[i]=ExtMapBuffer3[i]-50.0; } //--- memorize the number of values in the Relative Strength Index indicator bars_calculated=calculated; //--- return value of prev_calculated for next call return(rates_total);
Индикатор RSIAreaIndicator version 1.00 готов. Его можно скачать в конце статьи под именем "RSIAreaIndicatorv1.mq5". Теперь можно приступить к написанию советника RSIAreaEA version 1.00, который будет торговать по методу площадей.
4. Советник RSIAreaExpert version 1.00
Как и в случае с индикаторами, я рекомендую созданные советники размещать в отдельной папке. Например, моя папка для советников называется "MyExp". По аналогии с индикатором создадим заготовку советника RSIAreaExpert_v1. Важное уточнение: на одном из шагов нужно снять все галочки:
Рис. 7. Настройки при создании советника
Полученную заготовку советника вы можете просмотреть в конце статьи — советник сохранён под именем "RSIAreaExpert_v1_Step1.mq5".
4.1. Редактирование "шапки" советника
Добавим описание советника. Оно будет видно во вкладке "Общие" советника:
#property version "1.00" #property description "EA trades on \"Method areas\"" //+------------------------------------------------------------------+ //| Expert initialization function |
Описание не всегда хочется сразу заполнять, однако впоследствии вам очень поможет выработанное раз и навсегда правило: "При создании программы первое действие — это создание описания".
Советник будет использовать стандартную библиотеку — класс CTrade для выполнения торговых операций. Для этого нужно будет подключить класс CTrade и объявить переменную my_trade:
#property description "EA trades on \"Method areas\"" #include <Trade\Trade.mqh> //--- global variables CTrade my_trade; //+------------------------------------------------------------------+ //| Expert initialization function |
Также добавим три переменных (для хранения хэндла индикатора Relative Strength Index, для хранения текущей рассчитанной площади и одну вспомогательную):
//--- global variables CTrade my_trade; int handle; // variable for storing the handle of the iRSI indicator double RSIArea; // the calculated area double RSIOpen; // the auxiliary variable //+------------------------------------------------------------------+ //| Expert initialization function |
И последний шаг редактирования "шапки" советника — добавление входных параметров:
double RSIOpen; // the auxiliary variable //--- input parametres input int ExtRSIPeriod=13; // period of RSI input int AreaCondition=300; // area input ENUM_TIMEFRAMES period=PERIOD_M15; //+------------------------------------------------------------------+ //| Expert initialization function |
Переменная period введена исключительно для удобства тестирования в тестере стратегий — таким образом можно задавать разные диапазоны тестируемых периодов:
Рис. 8. Переменная period позволяет тестировать советник в широком диапазоне периодов
"Шапка" советника заполнена, теперь очередь функции OnInit(). В OnInit() будет только одна операция — получение хэндла индикатора на текущем символе (Symbol()) и на заданном периоде (period):
int OnInit() { //--- handle=iRSI(Symbol(),period,ExtRSIPeriod,PRICE_CLOSE); //--- if the handle is not created if(handle==INVALID_HANDLE) { //--- tell about the failure and output the error code PrintFormat("Failed to create handle of the iRSI indicator for the symbol %s/%s, error code %d", Symbol(), EnumToString(period), GetLastError()); //--- the indicator is stopped early return(INIT_FAILED); } //--- return(INIT_SUCCEEDED); }
Все эти изменения в процессе редактирования советника можно увидеть в файле "RSIAreaExpert_v1_Step2.mq5".
4.2. Вспомогательная функция RSIAreaFunc
Функция определения площади RSIAreaFunc() состоит из нескольких функциональных частей. Будем добавлять функционал постепенно. Первый блок (пояснения к нему — после кода):
void OnTick() { //--- } //+------------------------------------------------------------------+ //| Area calculation | //+------------------------------------------------------------------+ double RSIAreaFunc(int &RSIAreaShift,int BeginShift) { int shift,limit; double rsivalue,result; //--- get current RSI limit=Bars(Symbol(),period)-ExtRSIPeriod; if(limit>100) limit=100; double arr_rsi[]; ArrayResize(arr_rsi,limit); ArraySetAsSeries(arr_rsi,true); if(CopyBuffer(handle,0,0,limit,arr_rsi)==-1) { Print("CopyBuffer from iRSI failed, no data"); return(0); } return(result); }
Переменная limit отвечает за то, сколько значений индикатора iRSI мы будем копировать в массив arr_rsi[] при помощи CopyBuffer. Ограничим переменную limit значением "100" — то есть, всегда будем копировать последние 100 значений индикатора iRSI. Эти изменения редактирования советника можно увидеть в файле "RSIAreaExpert_v1_Step3.mq5".
4.3 Проверочный код работы функции CopyBuffer
Если Вам не совсем понятно, как работает функция CopyBuffer и какие значения содержатся в массиве под индексом "0", то можно написать простой проверочный код: в функции OnTick() напишем вызов вспомогательной функции RSIAreaFunc().
void OnTick() { //--- static int RSIAreaShift=0; RSIAreaFunc(RSIAreaShift,0); } //+------------------------------------------------------------------+ //| Area calculation | //+------------------------------------------------------------------+ double RSIAreaFunc(int &RSIAreaShift,int BeginShift)
В конце первого блока функции RSIAreaFunc() допишем вывод комментария — значения начального и конечного элементов массива arr_rsi[]:
if(CopyBuffer(handle,0,0,limit,arr_rsi)==-1) { Print("CopyBuffer from iRSI failed, no data"); return(0); } //--- Comment("arr_rsi[",limit-1,"]=",DoubleToString(arr_rsi[limit-1],2), "; arr_rsi[0]=",DoubleToString(arr_rsi[0],2)); return(result); }
Это проверочный код, он внесен только в файл RSIAreaExpert_v1_Step3_check.mq5, и его не будет в основном эксперте. Для проверки выполним следующее:
- скомпилировать (если это ещё не сделано ранее) файл советника RSIAreaExpert_v1_Step3_check.mq5;
- открыть новый график любого инструмента и поменять для него таймфрейм на M15 (так как по умолчанию во входных параметрах переменная period=PERIOD_M15);
- вставить на график индикатор RSI (меню "Вставка" -> "Индикаторы" -> "Осцилляторы" -> "Relative Strength Index" с такими настройками: "Период" 13 и "Применить к" Close);
- присоединить к графику советник RSIAreaExpert_v1_Step3_check.mq5.
На графике сразу станет видно, что значение элемента с индексом "0" в массиве arr_rsi соответствует значению индикатора RSI на самом правом баре:
Рис. 9. Проверка работы функции CopyBuffer
4.4. Продолжение редактирования вспомогательной функции
Следующий блок функции RSIAreaFunc():
if(CopyBuffer(handle,0,0,limit,arr_rsi)==-1) { Print("CopyBuffer from iRSI failed, no data"); return(0); } result=arr_rsi[0]-50.0; // values from the bar that has 0 index for(shift=BeginShift+1;shift<limit;shift++) { rsivalue=arr_rsi[shift]-50; if((result>0 && rsivalue<-3) || (result<0 && rsivalue>3)) { RSIAreaShift=shift; break; } result+=rsivalue; } return(result); }
Сначала переменной result присваивается значение индикатора RSI на самом правом баре минус 50. Затем идёт цикл по массиву arr_rsi, начиная с элемента с индексом "1" и до элемента с индексом limit-1. В этом цикле проверяется условие: "Было ли пересечение нулевой линии". Если пересечение было, то индекс бара (считаем справа налево) запоминается в переменную RSIAreaShift.
4.5. Функция OnTick() советника
Мы закончили редактировать вспомогательную функцию RSIAreaFunc(). Теперь очередь главной торговой функции OnTick(). Добавим следующий код в OnTick():
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- static int RSIAreaShift=0; int shift; double RSICurrent,RSILocalMin,RSILocalMax,value; double arr_rsi[1],rsi; MqlTick last_tick; //--- if(CopyBuffer(handle,0,0,1,arr_rsi)==-1) { Print("CopyBuffer from iRSI failed, no data"); return; } rsi=arr_rsi[0]; //--- if(!SymbolInfoTick(Symbol(),last_tick)) Print("SymbolInfoTick() failed, error = ",GetLastError()); //--- }
При помощи уже знакомой нам функции CopyBuffer получаем одно значение индикатора RSI на самом правом баре и далее присваиваем это значение переменной rsi -. Дальше в коде мы будем не раз обращаться к этой переменной. Затем получаем текущие цены по данному символу и храним эти цены в переменной last_tick.
Следующий блок кода обрабатывается при условии, что у нас есть открытая позиция по данному инструменту:
if(!SymbolInfoTick(Symbol(),last_tick)) Print("SymbolInfoTick() failed, error = ",GetLastError()); //--- check the conditions for opening a position if(!PositionSelect(Symbol())) { RSIArea=RSIAreaFunc(RSIAreaShift,0); //--- check for a chance to take a long position if(RSIArea<-AreaCondition) { my_trade.Buy(1.0,NULL,last_tick.ask,0.0,0.0,NULL); RSIOpen=rsi; return; } //---check for a chance to take a short position if(RSIArea>AreaCondition) { my_trade.Sell(1.0,NULL,last_tick.bid,0.0,0.0,NULL); RSIOpen=rsi; return; } RSIAreaShift=0; } //--- } //+------------------------------------------------------------------+ //| Area calculation |
В коде проверяются условия на открытие позиции: если рассчитанная на данный момент площадь (переменная RSIArea) меньше/больше входного параметра (AreaCondition), то, соответственно, будет открыта позиция Buy/Sell.
Дальше переменной RSICurrent присваивается значение переменной rsi (напомню, что в ней хранится одно значение индикатора RSI на самом правом баре) и проверяется условие выхода из функции OnTick():
- если позиция была открыта выше линии "50" (RSIOpen>50) и мы на данный момент находимся выше линии "50" (RSICurrent>50);
- если позиция была открыта ниже линии "50" (RSIOpen<50) и мы на данный момент находимся ниже линии "50" (RSICurrent<50):
RSIAreaShift=0; } RSICurrent=rsi; if(RSIOpen>50 && RSICurrent>50) return; if(RSIOpen<50 && RSICurrent<50) return; RSILocalMin = RSICurrent; RSILocalMax = RSICurrent; //--- } //+------------------------------------------------------------------+ //| Area calculation |
Следующий блок кода находит локальные минимумы/максимумы и присваивает эти значения переменным RSILocalMin и RSILocalMax:
RSILocalMin = RSICurrent; RSILocalMax = RSICurrent; //--- search local minimum/maximum if(RSIAreaShift>1) { double arr_rsi_1[]; ArrayResize(arr_rsi_1,RSIAreaShift); ArraySetAsSeries(arr_rsi_1,true); if(CopyBuffer(handle,0,0,RSIAreaShift,arr_rsi_1)==-1) { Print("CopyBuffer from iRSI failed, no data"); return; } for(shift=1; shift<RSIAreaShift; shift++) { value=arr_rsi_1[shift]; if(value<RSILocalMin && RSIArea>0) RSILocalMin=value; if(value>RSILocalMax && RSIArea<0) RSILocalMax=value; } } //--- } //+------------------------------------------------------------------+ //| Area calculation |
И, наконец, последний блок кода:
if(value>RSILocalMax && RSIArea<0) RSILocalMax=value; } } //--- check for rollback if(PositionSelect(Symbol())) { if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) { //--- сheck if it is time for closing if(RSILocalMax>=RSICurrent+4 && RSILocalMax>50) my_trade.PositionClose(Symbol(),20); } if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL) { //--- check, can it is time already be closing? if(RSILocalMin<=RSICurrent-4 && RSILocalMin<50) my_trade.PositionClose(Symbol(),20); } } //--- return; } //+------------------------------------------------------------------+ //| Area calculation |
Здесь (при наличии открытой позиции) проверяется условие закрытия позиции по правилу:
Пересечение осциллятором RSI линии 50 с последующим образованием локального максимума/минимума и откат от него на величину 4% шкалы.
Например, при долгом нахождении над линией 50 в какой-то момент имеем открытую позицию SELL. Затем значение индикатора начинает уменьшаться и достигает, допустим линии 40, после чего значение индикатора начинает увеличиваться (то есть, образуется локальный минимум). Сигналом к закрытию позиции будет момент, когда значение индикатора достигнет линии 44.
На этом создание советника RSIAreaExpert_v1 закончено. Файл "RSIAreaExpert_v1.mq5" можно скачать в конце статьи.
5. Тестирование советника RSIAreaExpert version 1.00 на разных периодах и символах
Тестирование советника RSIAreaExpert изначально проводилось на периоде графика H1 [1], но с 2004 года рынки сильно изменились, стали более волатильными, и поэтому для проверки работоспособности метода площадей тестирование решено было провести на большом диапазоне периодов: от M10 до H6. Также был существенно расширен диапазон площадей для тестирования: от 100 до 800. Временной период тестирования — с 2015.01.05 по 2016.01.05.
Итак, результаты тестирования советника RSIAreaExpert version 1 для символа AUDCAD:
Рис. 10. Результаты тестирования советника RSIAreaExpert version 1. Символ AUDCAD. Интервал площадей 100-800. Интервал периодов M10-H6
На периоде H2 мы видим хорошую плотность результатов. Можно ещё взять в расчёт период H3. Теперь посмотрим на рисунок ниже и оценим, сколько было сделок за год на символе AUDCAD при тестировании советника RSIAreaExpert version 1:
Рис. 11. Результаты тестирования советника RSIAreaExpert version 1. Символ AUDCAD. Интервал площадей 100-800. Интервал периодов M10-H6
На периодах H2 и H3 количество сделок за год колеблется в пределах 50. Это немного, а погрешность высока. Делаем вывод, что на символе AUDCAD стратегия метода площадей работает плохо.
Результаты тестирования советника RSIAreaExpert version 1 для символа AUDUSD:
Рис. 12. Результаты тестирования советника RSIAreaExpert version 1. Символ AUDUSD. Интервал площадей 100-800. Интервал периодов M10-H6
Если рассматривать прибыльность стратегии на символе AUDUSD, то можно рассматривать торговлю на периодах H2 и H3. На этих периодах параметр AreaCondition колеблется в пределах от 250 до 400. Для подтверждения обоснования торговли на периодах H2 и H3 нужно просмотреть количество трейдов за год на этих периодах:
Рис. 13. Результаты тестирования советника RSIAreaExpert version 1. Символ AUDUSD. Интервал площадей 100-800. Интервал периодов M10-H6
Как видим, оно катастрофически мало. Значит, и на AUDUSD по методу площадей торговать не рекомендуется.
Результаты тестирования советника RSIAreaExpert version 1 для символа EURUSD:
Рис. 14. Результаты тестирования советника RSIAreaExpert. Интервал площадей 100-800. Интервал периодов M10-H6
На рисунке 4 видно, что для периода M10 наблюдается хорошая плотность результатов прибыли для диапазона площадей от 400 до 550, для периода M12 — от 300 до 400 и для периода M15 — от 300 до 400. Более высокие периоды не рассматриваем, так как количество сделок для них за год слишком мало (см. рис. 5).
На рисунке 5 представлен график зависимостей количества сделок и прибыли для символа EURUSD:
Рис. 15. Результаты тестирования советника RSIAreaExpert. Интервал площадей 100-800. Интервал периодов M10-H6
Здесь хорошо видно, что на высоких периодах (от H1 до H6) количество сделок мизерное, что ставит под сомнение оправданность применения метода площадей на таких периодах. А вот на периодах M10, M12 и M15 количество сделок достаточно для подтверждения прибыльности метода площадей на этих таймфреймах. Определённо, символ EURUSD подходит для торговли по методу площадей.
Результаты тестирования советника RSIAreaExpert version 1 для символа GBPUSD:
Рис. 16. Результаты тестирования советника RSIAreaExpert version 1. Символ GBPUSD. Интервал площадей 100-800. Интервал периодов M10-H6
На символе GBPUSD хорошая плотность положительной прибыли для периода M20. Разброс параметра AreaCondition от 300 до 500.
Рис. 17. Результаты тестирования советника RSIAreaExpert version 1. Символ GBPUSD. Интервал площадей 100-800. Интервал периодов M10-H6
Для символа GBPUSD и на периоде M20 количество сделок за год в пределах от 140 до 250. Это, конечно, не фантастический показатель, но, тем не менее, его можно взять на заметку. Иными словами, торговля на символе GBPUSD методом площадей — занятие на любителя.
Результаты тестирования советника RSIAreaExpert version 1 для символа USDCAD:
Рис. 18. Результаты тестирования советника RSIAreaExpert version 1. Символ USDCAD. Интервал площадей 100-800. Интервал периодов M10-H6
На символе USDCAD я бы рассматривал только период M30, поскольку лишь на нем отмечается хорошая плотность положительной прибыли. При этом параметр AreaCondition изменяется в диапазоне от 280 до 550.
Рис. 19. Результаты тестирования советника RSIAreaExpert version 1. Символ USDCAD. Интервал площадей 100-800. Интервал периодов M10-H6
А вот количество сделок за год на этой валютной паре по таймфрейму M30 колеблется от 90 до 200. Это не очень много, поэтому метод площадей для символа USDCAD я бы не рекомендовал.
Результаты тестирования советника RSIAreaExpert version 1 для символа USDJPY:
Рис. 20. Результаты тестирования советника RSIAreaExpert version 1. Символ USDJPY. Интервал площадей 100-800. Интервал периодов M10-H6
На символе USDJPY выделяются два периода: M10 и M30. Параметр AreaCondition для периода M10 находится в пределах от 320 до 650, для периода M30 — в пределах от 550 до 600.
Рис. 21. Результаты тестирования советника RSIAreaExpert version 1. Символ USDJPY. Интервал площадей 100-800. Интервал периодов M10-H6
Для символа USDJPY количество сделок за год по методу площадей для периода M10 в пределах от 150 до 200, а для периода M30 в пределах 50 — 150. Таким образом, мы видим, что и здесь рекомендации по торговле весьма расплывчатые.
Заключение
Торговлю по методу площадей оказалось рано списывать со счетов. Правда, при текущих условиях на рынках система стала показывать убытки на периоде H1, хотя раньше [1] именно на нем отмечалась основная прибыль. На современном рынке самой прибыльной и результативной оказалась торговля по методу площадей на символе EURUSD на периодах M10, M12 и M15. Именно на этой валютной паре и на этих таймфреймах тестирование показало достаточное количество сделок в течение года.
Список использованной литературы
- Морозов И. В., Фатхуллин Р.Р. FOREX: от простого к сложному. Новые возможности с клиентским терминалом "MetaTrader". - М: ООО "Телетрейд", 2004. - 448 с.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Не понял из статьи, как именно рассчитывается площадь? Можно код и математическую формулу увидеть?
Я может и пропустил что-то, извиняюсь, если так....
Не понял из статьи, как именно рассчитывается площадь? Можно код и математическую формулу увидеть?
Я может и пропустил что-то, извиняюсь, если так....
Площадь вычисляется приближённо, методом прямоугольников. Но при одном условии - ширина такого прямоугольника равна "1".
Спасибо - идея ясна. А алгоритм можете показать с пошаговым описанием?
Для советника начиная с 4.2. Вспомогательная функция RSIAreaFunc
Для советника начиная с 4.2. Вспомогательная функция RSIAreaFunc
Если честно то, не вижу этого в коде - вижу поиск экстремумов, но не площади...