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

Alexander Fedosov | 16 февраля, 2016

Введение

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

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

 

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

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

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

Этап №1.

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

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

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

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

Этап №2.

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

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

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

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

  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 и привязать их показатели к позиции, которой мы входим в рынок? Для этого нужно выполнить следующие этапы:

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

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

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

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

Поэтому введем следующие категории для значения целей прибыли, которые будут прибавляться к изначальным 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. Описание категорий для значений целей прибыли

 

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

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

Теперь в полной реализации общий вид настройки торговой стратегии будет выглядеть следующим образом (рис.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. Он содержит следующие элементы:

Второй блок входных параметров 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, поскольку некорректные значения могут привести к ошибкам и неверной работе всей системы. Будьте внимательны!

 

Заключение

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

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