English 中文 Español Deutsch 日本語 Português
Создание ручных торговых стратегий с использованием нечеткой логики

Создание ручных торговых стратегий с использованием нечеткой логики

MetaTrader 4Трейдинг | 16 февраля 2016, 14:54
10 702 1
Alexander Fedosov
Alexander Fedosov

Введение

Стремительное развитие технологий привело к тому, что на современных валютных рынках усиливается тенденция использования автоматических торговых систем. Однако многие трейдеры по-прежнему работают в ручном режиме. Плюсы и минусы обоих подходов к торговле давно известны: автоторговля не слишком гибка к постоянным изменениям рынка, а ручная, наоборот, может быть избыточно гибкой из-за частого вмешательства человеческого фактора. По сути, в данном аспекте сравнения это две крайности одной и той же сущности.

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

 

Выбор ручной стратегии с четкой формализацией условий

Многие современные трейдеры решаются брать ответственность за вход и выход из своих позиций на себя, а не доверять это автоматическим системам. Им нужно разработать свою торговую стратегию, которая учитывала бы все возможные исходы поведения рынка. Затем требуется неукоснительно ей следовать и не поддаваться импульсам, провоцируемым страхом или жадностью.

Поэтому для начала нужно определиться с выбором торговой стратегии. Опишу три этапа ее построения.

  • Этап №1. Нахождение и определение инструментов, которые будут использованы в нашей стратегии.
  • Этап №2. Задание четких условий, при которых трейдер будет открывать свою позицию на рынке.
  • Этап №3. Задание четких условий, при которых позицию нужно будет закрыть с положительным или отрицательным результатом.

Этап №1.

На первом этапе в качестве примера я выбрал три индикатора для построения торговой стратегии:

  1. Индекс Среднего Направления Движения (Average Directional Movement Index, ADX). Это трендовый индикатор, определяющий силу текущего тренда.
  2. Осциллятор Индекс Относительной Бодрости (Relative Vigor Index, RVI).
  3. Индикатор Ускорения/Замедления Билла Уильямса Accelerator Oscillator(AC).

Выбранные общий вид и настройка торгового терминала MQL4:

Рис. 1. Общий вид настроек стратегии

Этап №2.

На втором этапе определим, как мы будем использовать выбранные инструменты, в каких условиях они будут работать, а также параметры позиции, которые мы будем задействовать для входа в рынок.

Начнем по порядку.

  • Первый наш индикатор — это ADX. Как видно на рис.1, заданный период индикатора равен 10. Кроме того, специально задан уровень для главной линии тренда (зеленого цвета), который равен 30. Значение, равное или выше него, мы будем считать положительным сигналом для входа в рынок. Следует отметить, что сигналом на покупку от этого индикатора будет ситуация, когда +DI (зеленая пунктирная линия) выше чем -DI (красная пунктирная). Соответственно, сигнал на продажу — обратная ситуация, когда -DI выше +DI.
  • Второй индикатор — AC. Здесь мы будем использовать сигналы, описанные в официальной документации. А именно, если значение индикатора ниже 0 и оно растет на анализируемом баре и двух предыдущих — это сигнал к покупке. Соответственно, если значение индикатора выше 0 и оно падает на анализируемом баре и двух предыдущих, мы получаем сигнал к продаже.
  • Третий индикатор — RVI. Зададим период его работы равным 10. В качестве условия на покупку определим момент, когда сигнальная (тонкая красная) линия пересекает основную (зеленую). При этом пересечении значение линии на анализируемом баре должно быть ниже нулевой отметки. Аналогично зададим условия для продажи: сигнальная линия пересекает основную, но значения находятся выше нуля.
  • Следующим условием работы будет часовой таймфрейм (H1).
  • Условие входа в позицию — подача одинаковых сигналов от всех трех выбранных индикаторов.
  • И, наконец, определимся с размером позиции. В качестве примера зададим: лот 0,01, Тейк Профит 50 пунктов, Стоп Лосс 30 пунктов.

Для большей ясности формализуем условия.

Вход в длинную позицию (сигнал к покупке)

  1. Основная зеленая линия индикатора ADX имеет значение, выше или равное 30, при этом значение +DI выше -DI.
  2. Значение AC растет на текущем баре, и оно выше, чем на предыдущих двух барах, которые, в свою очередь, тоже последовательно растут. Визуально это три столбца гистограммы зеленого цвета, каждый короче предыдущего, и все три находятся в отрицательной области.
  3. Сигнальная (тонкая красная) линия RVI пересекает основную (зеленую), обе растут, но все еще находятся ниже нулевой отметки.
  4. Покупаем лотом 0,01, выставляем Тейк Профит 50 пунктов и Стоп Лосс 30 пунктов.
Вход в короткую позицию (сигнал к продаже)
  1. Основная зеленая линия индикатора ADX имеет значение, больше или равное 30, при этом значение +DI ниже -DI.
  2. Значение AC падает на текущем баре, и оно ниже, чем на предыдущих двух барах, которые, в свою очередь, тоже последовательно снижаются. Визуально это три столбца гистограммы красного цвета, каждый короче предыдущего, и все три имеют значения выше нуля.
  3. Сигнальная (тонкая красная) линия RVI пересекает основную (зеленую), обе снижаются, но всё еще находятся в положительной области.
  4. Продаем лотом 0,01, выставляем Тейк Профит 50 пунктов и Стоп Лосс 30 пунктов.

Этап №3

Нам остается только определиться с выходом из позиции. В качестве условия для выхода зададим уже определенные нами ранее целевые показатели цены: достижение прибыли в 50 пунктов или срабатывание стопа в 30 пунктов.

Итак, наша торговая стратегия определена. Мы задали условия открытия и закрытия позиции, выбрали индикаторы и установили их рабочие параметры, определились с размерами позиции входа и их целями. И, наконец, мы решили, по каким событиям будет происходить выход из рынка.

Следующим этапом работы будет проверка созданной торговой стратегии в реальных условиях. Первое, что следует понимать, — идеальных стратегий в далекой перспективе и в абсолютно всех стадиях рынка не бывает. И трейдеры, использующие автоматическую торговлю, и те, кто торгуют в ручном режиме, часто наблюдают, что их система по-разному показывает себя в разных условиях. Также нередки случаи, когда изначальные условия в уже заданной торговой системе могли бы показывать лучший результат.

Например, по поводу нашей системы трейдер может заметить, что установленный Тейк Профит можно было бы сделать более высоким. Нет, не потому что ему просто хотелось бы получить больше, а потому что он постоянно анализировал свою систему, и его статистика показала: после закрытия удачных сделок цена еще некоторое время двигалась в нужном направлении. Поэтому у трейдера возникает вполне логичный вопрос: как правильно применить те статистические данные и наблюдения, которые он получил, к его торговой системе, улучшив ее результаты?

 

Недостатки четкой формализации и исправление их с помощью нечеткой логики

Рассмотрим применяемые в нашей системе индикаторы через призму теории нечеткой логики. В моей предыдущей статье я старался донести главное ее преимущество — гибкость к анализу тех частей торговых стратегий, где использовалась строгая категоризация. Нечеткая логика размывала строгие границы и давала более полное представление об оценке и реагировании системой в пограничных участках ее работы. Там же был показан пример более адаптивного подхода к работе применяемого нами индикатора ADX. Сначала использовалось строгое разделение на слабый, средний и сильный тренд, но затем эти категории размывались, и определение силы тренда уже не было строго привязано к субъективности значений индикатора.

Вернемся к нашей системе и зададимся вопросом: как всё это может нам помочь?

Представьте, что наш трейдер наблюдает за рынком и видит сигнал от первого своего индикатора: ADX достиг значения, к примеру, 32. Он это отмечает и ждет подтверждения от двух других индикаторов. И оно не заставляет себя долго ждать. Приходит сигнал от AC, при этом ADX вырос уже до 40. Через некоторое время сигнальная линия RVI пересекает основную, а значит, наконец-то достигнуты все три условия на вход в позицию. При этом ADX уже дотянулся до отметки 45. Но абсолютное значение ADX в нашей системе не столь важно. Главное — что оно выше 30. Поэтому трейдер следует своим правилам и входит в рынок лотом 0,01 с Тейк Профитом в 50 пунктов и Стоп Лоссом — в 30.

Теперь смоделируем другой вариант развития событий. Сначала ситуация развивается точно так же, как и в первом случае. ADX=32, приходит сигнал от AC, ADX параллельно достигает отметки 40. Но когда приходит последний недостающий сигнал на открытие позиции — от RVI — ADX подпрыгивает не до 45, а, скажем, до 55. Если сравнивать два описанных варианта, то второй сигнал сильнее предыдущего, но наш трейдер все равно открывает позицию тем же лотом и теми же значениями ТП и СЛ.

Здесь всплывает первый недостаток нашей стратегии: оценивается только наличие поступающего нам сигнала, без учета его качества. И даже если мы если оценим и определим категории, то в переходных областях точность оценки всё равно будет теряться.

Как же можно улучшить частный случай с индикаторами ADX, RVI и привязать их показатели к позиции, которой мы входим в рынок? Для этого нужно выполнить следующие этапы:

  • Определить четкие категории оценки силы тренда (ADX) и индекса относительной бодрости (RVI). Это будет входящий сигнал, на основе которого мы будем принимать дополнительное решение.
  • Определить четкие категории целей нашей позиции (в нашей стратегии это ТП и СЛ, хотя тут можно задать, например, размер лота). Это выходной сигнал, который будет корректировать нашу позицию на рынке с учетом силы тренда.
  • Описать категории входных и выходных сигналов функциями принадлежности теории нечетких множеств.
  • Создать интерфейс, который будет отображать рекомендации по изменению позиции начальной стратегии, исходя из новых условий.
  • Создать гибкие настройки изменения функций принадлежности, которые позволят при необходимости корректировать эту систему рекомендаций.

Для начала опишем первую входную переменную — значение силы тренда.

1. Задаем 4 категории силы тренда: слабый (low), умеренный (moderate), средний (medium) и сильный (high). Выглядеть это будет так:

Рис. 2. Визуальное разделение силы тренда на категории

2. Для задания категорий выходного сигнала нужно определиться, как категория ADX будет влиять на нашу позицию. Как правило, чем сильнее тренд, тем дольше он будет длиться. Поэтому поступим следующим образом: в зависимости от того, где находится ADX в момент, когда получены все три сигнала стратегии, будем увеличивать ТП на 10 - 50 пунктов.

Поэтому введем следующие категории для значения целей прибыли, которые будут прибавляться к изначальным 50 пунктам нашей стратегии.

  • Категория low_take: тренд слабый (Low), к целям добавляем 10 - 20 пунктов.
  • Категория mod_take: тренд умеренный (Moderate), к целям добавляем 20 - 30 пунктов.
  • Категория med_take: тренд средний (Medium), к целям добавляем 30 - 40 пунктов.
  • Категория high_take: тренд сильный (High), к целям добавляем 40 - 50 пунктов.

3. Следующим этапом опишем определенные выше условия с помощью функций принадлежности теории нечетких множеств. Описание четырех категорий тренда выглядит следующим образом:

Описания четырех категорий тренда

Рис. 3. Описание четырех категорий тренда нечеткой логикой

Как показано на рис.3, каждая из категорий была задана функциями принадлежности, а именно: low-тренд и high-тренд — двумя трапециевидными функциями, а категории moderate и medium — двумя треугольными.

Теперь определим то же самое для RVI.

1. Зададим категории для индекса относительной бодрости. Их тоже будет четыре: слабый (low), средний (medium), сильный (high), высший (higher). Выглядеть это будет так:

Рис. 4. Визуальное разделение индекса относительной бодрости на категории

2. Опишем введенные категории функциями принадлежности. Для описания категорий low и higher будут использоваться трапециевидные функции принадлежности, а для medium и high — треугольные.

Рис. 5. Описание категорий индекса RVI

Аналогично опишем четыре категории для значений целей прибыли: первая и четвертая категории(10-20 и 40-50 пунктов) — трапециевидными функциями, а две оставшиеся (20-30 и 30-40 пунктов) — треугольными. Так будет выглядеть описание нашего выходного сигнала.

Рис. 6. Описание категорий для значений целей прибыли

 

Реализация интерфейса панели для отображения рекомендаций по изменению позиции

При построении информационной панели мы выбираем четыре параметра для наблюдений:

  • Значение ADX. Только при выполнении заданных условий, а именно — 30 или выше.
  • Значение RVI. Только при условии, когда оно выше 0,1 (для сигнала к продаже), или ниже -0,1 (для сигнала к покупке).
  • Рекомендуемое количество пунктов, которые нужно прибавить к изначальной цели в 50.
  • Значение Тейк Профита в формате цены торгового инструмента (с учетом начальной цены и рекомендации по ее повышению).

Теперь в полной реализации общий вид настройки торговой стратегии будет выглядеть следующим образом (рис.6).

Рис. 7. Полная реализация и общий вид и настройка торговой стратегии

Теперь рассмотрим реализацию данной панели средствами MQL4 и библиотеки FuzzyNet.

Реализуем и рассмотрим ключевые логические блоки данной информационной панели средствами MQL4.

//+------------------------------------------------------------------+
//| FuzzyNet Panel                                                   |
//+------------------------------------------------------------------+
#property copyright "Alexander Fedosov"
#property version "1.0"
#property strict
#property link "https://www.mql5.com/ru/users/alex2356/"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Green
//+------------------------------------------------------------------+
//| Connecting libraries                                             |
//+------------------------------------------------------------------+
#include <Math\FuzzyNet\MamdaniFuzzySystem.mqh>

Определим начальные свойства и подключим библиотеку для работы с нечеткой логикой. Зададим нахождение панели в окне графика. Определим один индикаторный буфер и его цвет (зеленый) для указателя-стрелки рассматриваемого нами бара.

//--- Input parameters
input string  p1="==== Parameters ====";
input int fontSize=15;
input int adx_period=10;
input int rvi_period=10;
input int num_bar=0;
input int Screen_corner=4;
input color label_clr=Red;
input color textColor=Black;

Рассмотрим более подробно первый блок входных параметров Parameters. Он содержит следующие элементы:

  • fontSize — размер шрифта текстовой информации (рекомендуется диапазон 8 — 15).
  • adx_period — период работы индикатора ADX.
  • num_bar — номер бара, для которого рассчитывается система.
  • Screen_corner — угол отображения панели.
  • label_clr — цвет текста заголовков.
  • textColor — цвет текста значений.

Второй блок входных параметров Fuzzy Logic Parameters содержит в себе большинство параметров для гибкой настройки всех функций принадлежностей, описывающих как входные параметры (сила тренда ADX, индекс RVI), так и выходной (рекомендуемое значение пунктов цели прибыли).

input string  p2="==== Fuzzy Logic Parameters ====";
//--- ADX
input double in_term1a = 20;
input double in_term1b = 30;
input double in_term1c = 40;
input double in_term1d = 45;
input double in_term2a = 40;
input double in_term2b = 50;
input double in_term2c = 60;
input double in_term3a = 50;
input double in_term3b = 60;
input double in_term3c = 70;
input double in_term4a = 60;
input double in_term4b = 70;
input double in_term4c = 100;
input double in_term4d = 120;
//--- RVI
input double in_term1a1 = -0.25;
input double in_term1b1 = 0.1;
input double in_term1c1 = 0.15;
input double in_term1d1 = 0.25;
input double in_term2a1 = 0.15;
input double in_term2b1 = 0.25;
input double in_term2c1 = 0.35;
input double in_term3a1 = 0.25;
input double in_term3b1 = 0.35;
input double in_term3c1 = 0.45;
input double in_term4a1 = 0.4;
input double in_term4b1 = 0.45;
input double in_term4c1 = 1;
input double in_term4d1 = 1.2;
//--- Output
input double out_term1a = 5;
input double out_term1b = 10;
input double out_term1c = 15;
input double out_term1d = 22.5;
input double out_term2a = 17.5;
input double out_term2b = 25;
input double out_term2c = 32.5;
input double out_term3a = 27.5;
input double out_term3b = 35;
input double out_term3c = 42.5;
input double out_term4a = 37.5;
input double out_term4b = 45;
input double out_term4c = 50;
input double out_term4d = 60;
input double min_tp = 10;
input double max_tp = 50;


В следующем блоке объявляются переменные, названия заголовков, сам шаблон инфопанели (размер, положение, шрифт и прочие), а также устанавливаются параметры отображения элемента, указывающего на текущий бар (в нашем случае это стрелка).

int scaleX=55,scaleY=25,offsetX=35;
//--- создаем массив с названиями индикаторов
string signalName[]={"ADX_val:","RVI_val:","TP_plus:","TP_prc:"};
double adx,adx_di_minus,adx_di_plus,rvi,rvi_sig,mdm;
double Buffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(fontSize>15 || fontSize<8)
     {
      Print("ERROR: Incorrect fontSize. Must be 8-15.");
      Alert("ERROR: Incorrect fontSize. Must be 8-15.");
      return(0);
     }
   if(Screen_corner>4 || Screen_corner<1)
     {
      Print("ERROR: Incorrect Screen_corner. Must be 1-4.");
      Alert("ERROR: Incorrect Screen_corner. Must be 1-4.");
      return(0);
     }
//---
   SetIndexStyle(0,DRAW_ARROW,EMPTY,1);
   SetIndexArrow(0,234);
   SetIndexBuffer(0,Buffer);
   ArrayInitialize(Buffer,0.0);
//---
   for(int y=0;y<4;y++)
     {
      ObjectCreate("lb_ind_nm"+string(y),OBJ_LABEL,0,0,0,0,0);
      //--- изменяем угол привязки    
      ObjectSet("lb_ind_nm"+string(y),OBJPROP_SELECTABLE,false);
      ObjectSet("lb_ind_nm"+string(y),OBJPROP_CORNER,Screen_corner);
      ObjectSet("lb_ind_nm"+string(y),OBJPROP_XDISTANCE,offsetX-30);
      ObjectSet("lb_ind_nm"+string(y),OBJPROP_YDISTANCE,y*scaleY+20);
      ObjectSetText("lb_ind_nm"+string(y),signalName[y],fontSize,"Tahoma",label_clr);
     }
//---
   for(int y=0;y<4;y++)
     {
      ObjectCreate("lb_ind0"+string(y),OBJ_LABEL,0,0,0,0,0);
      //--- изменяем угол привязки
      ObjectSet("lb_ind0"+string(y),OBJPROP_SELECTABLE,false);
      ObjectSet("lb_ind0"+string(y),OBJPROP_CORNER,Screen_corner);
      ObjectSet("lb_ind0"+string(y),OBJPROP_XDISTANCE,scaleX+offsetX);
      ObjectSet("lb_ind0"+string(y),OBJPROP_YDISTANCE,y*scaleY+20);
      ObjectSetText("lb_ind0"+string(y),"",fontSize,"Tahoma",textColor);
     }
   return(INIT_SUCCEEDED);
  }


Теперь рассмотрим основной блок обработки сигналов, исходящих от индикаторов ADX и RVI.

Задаются условия, при которых значения индикаторов удовлетворяют сигналам на покупку и продажу. При их совпадении значения обрабатываются функцией mamdani(double t, double v) и выводятся в панель. Всё это имеет следующий вид: текущие значения индикаторов с указанием на то, buy-сигнал мы получили или sell; рекомендуемый ТП (в пунктах и в численном значении).

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   Buffer[num_bar]=High[num_bar]+20*_Point;
   adx=NormalizeDouble(iADX(_Symbol,PERIOD_CURRENT,adx_period,PRICE_CLOSE,MODE_MAIN,num_bar),_Digits);
   adx_di_plus=NormalizeDouble(iADX(_Symbol,PERIOD_CURRENT,adx_period,PRICE_CLOSE,MODE_PLUSDI,num_bar),_Digits);
   adx_di_minus=NormalizeDouble(iADX(_Symbol,PERIOD_CURRENT,adx_period,PRICE_CLOSE,MODE_MINUSDI,num_bar),_Digits);
//---
   rvi=NormalizeDouble(iRVI(_Symbol,PERIOD_CURRENT,rvi_period,MODE_MAIN,num_bar),_Digits);
   rvi_sig=NormalizeDouble(iRVI(_Symbol,PERIOD_CURRENT,rvi_period,MODE_SIGNAL,num_bar),_Digits);
//---   
   if(adx>30 && adx_di_plus>adx_di_minus && rvi>rvi_sig && rvi<-0.1)
     {
      mdm=MathCeil(mamdani(adx,MathAbs(rvi)));
      ObjectSetText("lb_ind00","buy_signal: "+DoubleToString(adx,_Digits),fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind01","buy_signal: "+DoubleToString(rvi,_Digits),fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind02",DoubleToString(mdm,0),fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind03",DoubleToString(tp_prc(mdm),_Digits),fontSize,"Tahoma",textColor);
     }
   else if(adx>30 && adx_di_plus<adx_di_minus && rvi<rvi_sig && rvi>0.1)
     {
      mdm=MathCeil(mamdani(adx,rvi));
      ObjectSetText("lb_ind00","sell_signal: "+DoubleToString(adx,_Digits),fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind01","sell_signal: "+DoubleToString(rvi,_Digits),fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind02",DoubleToString(mdm,0),fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind03",DoubleToString(tp_prc(mdm),_Digits),fontSize,"Tahoma",textColor);
     }
   else
     {
      ObjectSetText("lb_ind00","no_signal",fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind01","no_signal",fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind02"," - ",fontSize,"Tahoma",textColor);
      ObjectSetText("lb_ind03"," - ",fontSize,"Tahoma",textColor);
     }
   return(rates_total);
  }

Функция создает систему нечеткой логики. Она содержит два входящих сигнала от индикаторов — trend и vigor (каждый из которых состоит из четырех термов, описываемых функциями принадлежности) и один исходящий — signal. Также в систему включены четыре правила, которыми связываются входящие и исходящий сигналы.

//+------------------------------------------------------------------+
//| Функция создания и расчета системы на основе нечеткой логики     |
//+------------------------------------------------------------------+
double mamdani(double t,double v)
  {
   double res=0;
//--- Mamdani Fuzzy System  
   MamdaniFuzzySystem *fsSignal=new MamdaniFuzzySystem();
//--- Create input variables for the system
   FuzzyVariable *fsTrend=new FuzzyVariable("trend",30.0,100.0);
   FuzzyVariable *fsVigor=new FuzzyVariable("vigor",0.1,1.0);
//--- ADX
   fsTrend.Terms().Add(new FuzzyTerm("low", new TrapezoidMembershipFunction(in_term1a, in_term1b, in_term1c, in_term1d)));
   fsTrend.Terms().Add(new FuzzyTerm("moderate", new TriangularMembershipFunction(in_term2a, in_term2b, in_term2c)));
   fsTrend.Terms().Add(new FuzzyTerm("medium", new TriangularMembershipFunction(in_term3a, in_term3b, in_term3c)));
   fsTrend.Terms().Add(new FuzzyTerm("high",new TrapezoidMembershipFunction(in_term4a, in_term4b, in_term4c, in_term4d)));
   fsSignal.Input().Add(fsTrend);
//--- RVI
   fsVigor.Terms().Add(new FuzzyTerm("low", new TrapezoidMembershipFunction(in_term1a1, in_term1b1, in_term1c1, in_term1d1)));
   fsVigor.Terms().Add(new FuzzyTerm("medium", new TriangularMembershipFunction(in_term2a1, in_term2b1, in_term2c1)));
   fsVigor.Terms().Add(new FuzzyTerm("high", new TriangularMembershipFunction(in_term3a1, in_term3b1, in_term3c1)));
   fsVigor.Terms().Add(new FuzzyTerm("higher",new TrapezoidMembershipFunction(in_term4a1, in_term4b1, in_term4c1, in_term4d1)));
   fsSignal.Input().Add(fsVigor);
//--- Create Output
   FuzzyVariable *fvSignal=new FuzzyVariable("signal",min_tp,max_tp);
   fvSignal.Terms().Add(new FuzzyTerm("low_take", new TrapezoidMembershipFunction(out_term1a, out_term1b, out_term1c, out_term1d)));
   fvSignal.Terms().Add(new FuzzyTerm("mod_take", new TriangularMembershipFunction(out_term2a, out_term2b, out_term2c)));
   fvSignal.Terms().Add(new FuzzyTerm("med_take", new TriangularMembershipFunction(out_term3a, out_term3b, out_term3c)));
   fvSignal.Terms().Add(new FuzzyTerm("high_take", new TrapezoidMembershipFunction(out_term4a, out_term4b, out_term4c, out_term4d)));
   fsSignal.Output().Add(fvSignal);
//--- Create four Mamdani fuzzy rule
   MamdaniFuzzyRule *rule1 = fsSignal.ParseRule("if (trend is low) and (vigor is low) then signal is low_take");
   MamdaniFuzzyRule *rule2 = fsSignal.ParseRule("if (trend is moderate) and (vigor is medium) then signal is mod_take");
   MamdaniFuzzyRule *rule3 = fsSignal.ParseRule("if (trend is medium) and (vigor is high) then signal is med_take");
   MamdaniFuzzyRule *rule4 = fsSignal.ParseRule("if (trend is high) and (vigor is higher) then signal is high_take");
//--- Add four Mamdani fuzzy rule in system
   fsSignal.Rules().Add(rule1);
   fsSignal.Rules().Add(rule2);
   fsSignal.Rules().Add(rule3);
   fsSignal.Rules().Add(rule4);
//--- Set input value
   CList *in=new CList;
   Dictionary_Obj_Double *p_od_adx=new Dictionary_Obj_Double;
   Dictionary_Obj_Double *p_od_rvi=new Dictionary_Obj_Double;
   p_od_adx.SetAll(fsTrend,t);
   p_od_rvi.SetAll(fsVigor,v);
   in.Add(p_od_adx);
   in.Add(p_od_rvi);
//--- Get result
   CList *result;
   Dictionary_Obj_Double *p_od_out;
   result=fsSignal.Calculate(in);
   p_od_out=result.GetNodeAtIndex(0);
   res=NormalizeDouble(p_od_out.Value(),_Digits);
//---
   delete in;
   delete result;
   delete fsSignal;
   return res;
  }


Перейдем к последнему блоку — "Вспомогательные функции". Первая из них, tp_prc(double take), конвертирует значение ТП в пунктах в численное значение цены текущего валютного инструмента. Вторая определяет количество знаков в текущем валютном инструменте.

//+------------------------------------------------------------------+
//| Функция определения целей прибыли                                |
//+------------------------------------------------------------------+
double tp_prc(double take)
  {
   int tip;
   double opr,tp;
   take+=50;
   adx_di_plus=NormalizeDouble(iADX(_Symbol,PERIOD_CURRENT,adx_period,PRICE_CLOSE,MODE_PLUSDI,num_bar),_Digits);
   adx_di_minus=NormalizeDouble(iADX(_Symbol,PERIOD_CURRENT,adx_period,PRICE_CLOSE,MODE_MINUSDI,num_bar),_Digits);
//---
   if(adx_di_plus>adx_di_minus)
      tip=0;
   else if(adx_di_plus<adx_di_minus)
      tip=1;
//---
   switch(tip)
     {
      case 0:
         opr=Ask;
         break;
      case 1:
         opr=Bid;
         break;
     }
   if(MathMod(tip,2.0)==0.0)
     {
      tp=opr+take*Dig()*_Point;
     }
   else
     {
      tp=opr-take*Dig()*_Point;
     }
   return(tp);
  }
//+------------------------------------------------------------------+
//| Функция возврата количества десятичных знаков после запятой      |
//+------------------------------------------------------------------+
int Dig()
  {
   return((_Digits==5 || _Digits==3 || _Digits==1)?10:1);
  }
//+------------------------------------------------------------------+

Также хотелось бы обратить внимание на правильность настройки и перепроверку корректности параметров в разделе Fuzzy Logic Parameters при тестировании. Рекомендую опираться на изначальные их графические представления на рис. 3, 5, 6, поскольку некорректные значения могут привести к ошибкам и неверной работе всей системы. Будьте внимательны!

 

Заключение

В заключение подведем итоги и сделаем выводы.

  • Первая часть работы по созданию ручной торговой стратегии с применением нечеткой логики — разработка четко формализованных правил этой стратегии. Это было рассмотрено на этапах №№1 — 3.
  • Затем необходимо определить недостатки четкой формализации в тех местах, где присутствует строгая категоризация каких-либо оценочных блоков или параметров. В приведенном примере была найдена часть стратегии, которая не позволяла гибко определять момент входа в рынок.
  • Далее все четкие категории описываются с помощью теории нечетких множеств и, таким образом, становятся более гибкими. Теперь в пограничных значениях может существовать принадлежность не к одной конкретной категории, как раньше, а к обеим сразу, но в разных степенях.
  • Эта стратегия реализуется в виде индикатора, панели либо алерта. В данной статье была выбрана панель на языке MQL4.
Мы рассмотрели возможность улучшения ручной торговой стратегии с использованием теории нечетких множеств. На примере было подробно показано, как уже сформированная торговая стратегия модифицируется и дополняется, с помощью нечеткой логики избавляясь от найденных недостатков.
Прикрепленные файлы |
fuzzy_panel.mq4 (11.86 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (1)
Peter Stacenco
Peter Stacenco | 4 июл. 2016 в 13:45
  • "Третий индикатор — RVI. Зададим период его работы равным 10. В качестве условия на покупку определим момент, когда сигнальная (тонкая красная) линия пересекает основную (зеленую). При этом пересечении значение линии на анализируемом баре должно быть ниже нулевой отметки. Аналогично зададим условия для продажи: сигнальная линия пересекает основную, но значения находятся выше нуля."

С этим не совсем понятно. Как вы выделили основную линию? Или поставили индикатор и зелёную линию назначили основной? Я без претензий, хочу разобраться.

Просто по идеи для сигнала на покупку нужно чтобы АС был ниже нуля и зелёная линия пересекла красную снизу вверх.... 

Как быстро добавить панель управления к индикатору и советнику Как быстро добавить панель управления к индикатору и советнику
Вы хотите добавить к своему индикатору или советнику графическую панельку для удобного и быстрого управления, но не знаете, как это сделать? В этой статье шаг за шагом я покажу как "прикрутить" панель диалога со входными параметрами к вашей MQL4/MQL5-программе.
Графические интерфейсы II: Элемент "Пункт меню" (Глава 1) Графические интерфейсы II: Элемент "Пункт меню" (Глава 1)
В второй части серии будет показан процесс разработки таких элементов интерфейса, как главное меню и контекстное меню. Также затронем тему рисования элементов и для этого создадим специальный класс. Очень широко будет освещен такой вопрос, как управление событиями программы, в том числе и пользовательскими.
Графические интерфейсы II: Элементы "Разделительная линия" и "Контекстное меню" (Глава 2) Графические интерфейсы II: Элементы "Разделительная линия" и "Контекстное меню" (Глава 2)
В этой статье мы создадим элемент «Разделительная линия». Его тоже можно будет использовать не только как независимый элемент интерфейса, но и как часть многих других элементов. После этого у нас будет всё необходимое для разработки класса контекстного меню, которое тоже будет подробно рассмотрено в этой статье. Кроме этого, вносятся необходимые дополнения в класс, который является базой для хранения указателей на все элементы графического интерфейса приложения.
Универсальный торговый эксперт: Торговля в группе и управление портфелем стратегий (Часть 4) Универсальный торговый эксперт: Торговля в группе и управление портфелем стратегий (Часть 4)
В заключительной части серии статей о торговом движке CStrategy мы рассмотрим одновременную работу нескольких торговых алгоритмов, научимся загружать стратегии из XML-файлов, а также представим простую панель для выбора экспертов, находящихся внутри одного исполняемого модуля, и управления их торговыми режимами.