ртеун. кст. Пример построения индикатора с использованием Fuzzy Logic
Скачать 347.76 Kb.
|
РУБЕЖНЫЙ КОНТРОЛЬ 3 по дисциплине «Интеллектуальные информационные системы» тема «Пример построения индикатора с использованием Fuzzy Logic»
Москва – 2021 г. ОглавлениеВведение 3 Пример использования 3 Функция принадлежности 4 Составляем программный код 6 Список использованных источников: 18 ВведениеМатематическая теория нечётких множеств позволяет описывать нечёткие понятия и знания, оперируя этими знаниями, и делать нечёткие выводы. При этом нечёткие системы позволяют повысить качество продукции при уменьшении ресурса и энергозатрат и обеспечивают более высокую устойчивость к воздействию мешающих факторов. Математическая теория нечетких множеств и нечёткая логика является обобщением классической теории множеств и формальной логики. Данные понятия были предложены американским учёным З. Лотфи в 1965 году. Основной причиной появления новой теории стоило наличие нечётких и приближённых рассуждений при описании человеком процессов, систем, объектов. Спектр приложений нечётких моделей и методов широк и от управления процессом отправления и остановки поезда метрополитена управление грузовыми лифтами и доменной печью до стиральных машин, пылесосов и печей СВЧ. Нечёткая логика обеспечивает эффективные средства отображения, неопределённостей и неточностей реального мира. Пример использованияОпишем функцию принадлежности для высказывания "горячий кофе": температуру кофе следует рассматривать в диапазоне от 0 до 100 градусов Цельсия по той простой причине, что при температуре меньше 0 градусов это будет лед, а выше 100 градусов - пар. Очевидно, что чашка кофе с температурой 20 градусов никак не может быть названа горячей, то есть функция принадлежности кофе к категории "горячий" равна 0, а вот чашка кофе с температурой 70 градусов уже однозначно принадлежит к категории "горячий" и соответственно значение функции в этом случае равно 1. Что касается значений температур, находящихся между этими двумя крайними значениями, то ситуация неоднозначна. Т.к. для одного человека чашка кофе с температурой 55 градусов будет "горячей", а для другого - "не слишком горячей". В этом и заключается "нечеткость". Тем не менее примерный вид функции принадлежности мы можем себе представить: она "монотонно возрастающая": На рисунке, приведенном выше, изображена "кусочно-линейная" функция принадлежности. Таким образом, функция может быть задана следующим аналитическим выражением: Функции подобного вида мы и будем использовать для нашего индикатора. Функция принадлежностиВ задачу любого технического индикатора, в той или иной мере, входит определение состояния рынка на данный момент (Флет, Тренд вверх, Тренд вниз), а также генерация сигналов на заключение сделки и выход из нее. Как это можно осуществить при помощи функций принадлежности? Достаточно просто. Для начала нам нужно определиться с граничными условиями. Путь граничным условием для определения «100% Тренд вверх» будет пересечение EMA с периодом 2, построенной по типичной цене (H+L+C)/3, с верхней границей конверта Envelopes с параметрами 8, 0.08, SMA, Close., а «100% тренд вниз» с нижней границей. Все, что между ними, будем считать флетом. Для пущей важности добавим еще один конверт с параметрами 32, 0.15, SMA, Close. В итоге мы должны получить две идентичные функции принадлежности. Сигналом к покупке будет ситуация, когда обе функции будут равны 1, к продаже соответственно -1. Т.к. графики функции удобно строить в диапазоне от -1 до 1, результирующий график получим путем среднего арифметического результатов двух функций F(x)= (f1(x)+f2(x))/2. Вот так это выглядит на чарте: В таком случае функция принадлежности примет следующее графическое отображение: Аналитически его можно записать в следующем виде: , где a и b верхняя и нижняя линии конверта соответственно, а х - значение EMA(2). С функцией определились, теперь переходим к написанию кода индикатора. Составляем программный кодСначала определимся с тем, что и как будем рисовать. Результаты вычислений функции принадлежности будем выводить линией - красной и синей соответственно. Среднее арифметическое будем рисовать гистограммой от нулевой линии и раскрашивать в зависимости от значения результирующей функции в пять цветов: Для этого будем использовать стиль рисования DRAW_COLOR_HISTOGRAM. Для выдачи сигналов на покупку и продажу нарисуем прямоугольники синего и красного цветов над теми полосками гистограммы, значение которых равно 1 или -1. Запускаем MetaEditor и приступаем. Создать->Пользовательский индикатор->Далее... Заполняем окошко "параметры": Создаем буферы: Жмем кнопку "Готово", получаем исходный код и начинаем его дорабатывать. Во-первых, определимся с количеством буферов. Семь у нас уже создал мастер (5 для данных, 2 для цвета). Нам понадобится еще 5. #property indicator_minimum -1.4 // Ставим дробные значения #property indicator_maximum 1.4 // мастер экспертов почему-то игнорирует дробные части #property indicator_buffers 12 // Меняем значение с 7 на 12 (добавилось еще 5 буферов) Редактируем входные параметры: input string txt1="----------"; input int Period_Fast=8; input ENUM_MA_METHOD Method_Fast = MODE_SMA; /*Метод усреднения*/ //метод усреднения скользящей input ENUM_APPLIED_PRICE Price_Fast = PRICE_CLOSE; input double Dev_Fast=0.08; input string txt2="----------"; input int Period_Slow=32; input ENUM_MA_METHOD Method_Slow = MODE_SMA; input ENUM_APPLIED_PRICE Price_Slow = PRICE_CLOSE; input double Dev_Slow=0.15; /*Параметр отклонения*/ input string txt3="----------"; input int Period_Signal=2; input ENUM_MA_METHOD Method_Signal = MODE_EMA; input ENUM_APPLIED_PRICE Price_Signal = PRICE_TYPICAL; input string txt4="----------"; Очень удобным нововведением является комментарий, стоящий за объявленной переменной, его текст вставляется в окошко параметров индикатора. Также очень радует возможность создания списков: Резервируем переменные под хендлы индикаторов и индикаторные буферы: int Envelopes_Fast; // Быстрый конверт int Envelopes_Slow; // Медленный конверт int MA_Signal; // Сигнальная линия double Env_Fast_Up[]; // Верхняя граница быстрого конверта double Env_Fast_Dn[]; // Нижняя граница быстрого конверта double Env_Slow_Up[]; // Верхняя граница медленного конверта double Env_Slow_Dn[]; // Нижняя граница медленного конверта double Mov_Sign[]; // Сигнальная линия Теперь переходим в функцию OnInit(). Наведем немного красоты: зададим имя индикатору и уберем лишние десятичные нули: IndicatorSetInteger(INDICATOR_DIGITS,1); // зададим точность отображения, большая нам не нужна string name; // имя индикатора StringConcatenate(name, "FLE ( ", Period_Fast, " , ", Dev_Fast, " | ", Period_Slow, " , ", Dev_Slow, " | ", Period_Signal, " )"); IndicatorSetString(INDICATOR_SHORTNAME,name); и добавим недостающие буферы: SetIndexBuffer(7,Env_Fast_Up,INDICATOR_CALCULATIONS); SetIndexBuffer(8,Env_Fast_Dn,INDICATOR_CALCULATIONS); SetIndexBuffer(9,Env_Slow_Up,INDICATOR_CALCULATIONS); SetIndexBuffer(10,Env_Slow_Dn,INDICATOR_CALCULATIONS); SetIndexBuffer(11,Mov_Sign,INDICATOR_CALCULATIONS); Параметр INDICATOR_CALCULATIONS означает, что данные буфера не будут выводиться на график, а предназначены только для промежуточных расчетов. Обратите внимание на то, как обьявляются индикаторы с буфером цвета: SetIndexBuffer(4,SignalBuffer1,INDICATOR_DATA); // Сперва все буферы индикатора SetIndexBuffer(5,SignalBuffer2,INDICATOR_DATA); // т.к это Color Histogram2 то у него 2 буфера данных SetIndexBuffer(6,SignalColors,INDICATOR_COLOR_INDEX);// а потом идет буфер цвета. заполняем хендлы: Envelopes_Fast = iEnvelopes(NULL,0,Period_Fast,0,Method_Fast,Price_Fast,Dev_Fast); Envelopes_Slow = iEnvelopes(NULL,0,Period_Slow,0,Method_Slow,Price_Slow,Dev_Slow); MA_Signal = iMA(NULL,0,Period_Signal,0,Method_Signal,Price_Signal); С функцией OnInit() все. Теперь создадим функцию, которая будет рассчитывать значение функции принадлежности: double Fuzzy(double x,double a, double c) { double F; if (a else if (x<=a && x>=c) F=(1-2*(a-x)/(a-c));// Флет else if (x return (F); } Подготовительный этап закончился. Переменные и буферы объявлены, хендлы присвоены. Приступаем непосредственно к основной функции OnCalculate(). Для начала запишем в промежуточные буферы значения необходимых нам индикаторов. Воспользуемся функцией CopyBuffer(): CopyBuffer(Envelopes_Fast, // Хендл индикатора UPPER_LINE, // Буфер индикатора 0, // Откуда начинаем 0 - с самого начала rates_total, // Сколько копируем - Все Env_Fast_Up); // Буфер в который записываются значения // - остальные по аналогии CopyBuffer(Envelopes_Fast,LOWER_LINE,0,rates_total,Env_Fast_Dn); CopyBuffer(Envelopes_Slow,UPPER_LINE,0,rates_total,Env_Slow_Up); CopyBuffer(Envelopes_Slow,LOWER_LINE,0,rates_total,Env_Slow_Dn); CopyBuffer(MA_Signal,0,0,rates_total,Mov_Sign); Здесь необходимо добавить код для оптимизации вычислений (пересчет только последнего бара) // объявляем переменную start, в ней будет храниться индекс бара с которого будет осуществляться // пересчет индикаторных буферов. int start; if (prev_calculated==0) // если ни один бар не просчитан { start = Period_Slow; // до этого значения не все индикаторы просчитаны поэтому исполнять код не имеет смысла } else start=prev_calculated-1; for (int i=start;i { // Здесь будет записан весь оставшийся код } Кода осталось совсем чуть-чуть. Задаем параметры x, a, b, производим расчет значения функции принадлежности и записываем его в соответствующий буфер: double x = Mov_Sign[i]; // Сигнал // Зададим параметры первой функции принадлежности: double a1 = Env_Fast_Up[i]; // Верхняя граница double b1 = Env_Fast_Dn[i]; // вычислим значение первой функции принадлежности и запишем ее в буфер Rule1Buffer[i] = Fuzzy(x,a1,b1); // Зададим параметры второй функции принадлежности: double a2 = Env_Slow_Up[i]; // Верхняя граница double b2 = Env_Slow_Dn[i]; // вычислим значение второй функции принадлежности и запишем ее в буфер Rule2Buffer[i] = Fuzzy(x,a2,b2); Две индикаторные линии построены. Теперь рассчитаем результирующее значение. ResultBuffer[i] = (Rule1Buffer[i]+Rule2Buffer[i])/2; Далее раскрасим полоски гистограммы соответствующими цветами: т.к. цветов пять, то ResultColors[i] может принимать значение от 0 до 4. Вообще цветов может быть до 64, так что это невероятная возможность для полета фантазии. for (int ColorIndex=0;ColorIndex<=4;ColorIndex++) { if (MathAbs(ResultBuffer[i])>0.2*ColorIndex && MathAbs(ResultBuffer[i])<=0.2*(ColorIndex+1)) { ResultColors[i] = ColorIndex; break; } } Далее нарисуем сигнальные прямоугольники, нам понадобится стиль рисования DRAW_COLOR_HISTOGRAM2. У него два буфера данных, между которыми строится полоска гистограммы и один буфер цвета. Значения буферов данных всегда будут постоянными: 1.1 и 1.3 для сигнала на покупку, -1.1 и -1.3 для сигнала на продажу соответственно. Значение EMPTY_VALUE будет соответствовать отсутствию сигнала. if (ResultBuffer[i]==1) { SignalBuffer1[i]=1.1; SignalBuffer2[i]=1.3; SignalColors[i]=1; } else if (ResultBuffer[i]==-1) { SignalBuffer1[i]=-1.1; SignalBuffer2[i]=-1.3; SignalColors[i]=0; } else { SignalBuffer1[i]=EMPTY_VALUE; SignalBuffer2[i]=EMPTY_VALUE; SignalColors[i]=EMPTY_VALUE; } Жмем "Компилировать" и вуаля! Список использованных источников:https://www.netkom.by/docs/N31-Nechetkaya-logika.pdf Fuzzy-технология: математические основы. Практика моделирования в экономике (Автор: Бочарников Виктор Павлович) Александр Леоненков Нечеткое моделирование в среде MATLAB и fuzzyTECH / Александр Леоненков. - М.: БХВ-Петербург, 2005 https://www.mql5.com/ru/articles/178 |