퍼지 로직 (Fuzzy Logic)을 이용한 인디케이터 생성의 간단한 예
소개
금융 시장 분석을 위한 다양한 방법의 사용은 최근 몇 년 동안 트레이더들 사이에서 점점 더 인기를 얻고 있습니다. 나는 몇 개의 코드 라인을 작성하여 좋은 인디케이터를 만드는 방법을 보여주고 싶습니다. 또한 fuzzy logic의 기본 사항을 간략하게 설명하겠습니다.
이 문제에 관심이 있고 더 깊이 탐구하고 싶은 사람은 누구나 다음 글들을 읽어볼 수 있습니다.
2. Bocharnikov V. "퍼지 기술 (Fuzzy Technology): 수학적 배경. 경제학 시뮬레이션 실습"(in Russian).
3. S.N. Sivanandam, S. Sumathi, S.N. Deepa. MATLAB을 사용한 퍼지 로직 (Fuzzy Logic) 소개.
4. C. Kahraman. 응용 프로그램이있는 퍼지 엔지니어링 경제학 (퍼지 및 소프트 컴퓨팅 연구).
1. 퍼지 로직 (Fuzzy Logic) 기초
"... 조금만 더 ...", "... 너무 빠르다 ...", "... 거의 아무것도 ..."와 같은 단순한 표현의 의미를 어떻게 컴퓨터에 설명할 수 있습니까? 사실, 퍼지 세트 이론 요소를 사용하거나 소위 "멤버십 기능"을 사용하면 가능합니다. 다음은 А의 예입니다. Leonenkov의 책:
"뜨거운 커피" 라는 문구의 멤버십 기능을 설명해 봅시다. 커피 온도는 0도 이하의 온도에서는 얼음으로 바뀌고 그 이상의 온도에서는 얼음으로 변하기 때문에 섭씨 0도에서 100도 사이의 범위로 간주되어야 합니다. 100도 이상의 온도에서는 증발하니까요. 온도가 20도인 커피 한 잔은 뜨겁다고 할 수 없습니다. 즉, "뜨거운" 카테고리의 멤버십 기능은 0과 같고 온도가 70 도인 커피 한 잔은 확실히 "뜨거운" 범주이므로 이 경우 함수 값은 1과 같습니다.
이 두 극단 값 사이에 있는 온도 값은 상황이 그렇게 명확하지 않습니다. 어떤 사람들은 온도가 55 도인 커피 한 잔을 "뜨겁다"고 생각하는 반면, 다른 사람들은 "그다지 뜨겁지 않다"고 생각할 수 있습니다. 이것이 "모호함 (fuzziness)"입니다.
그럼에도 불구하고 우리는 멤버십 함수의 대략적인 모습을 상상할 수 있습니다. 이는 "단조롭게 증가"합니다.
위 그림은 "piecewise linear" 멤버십 기능을 보여줍니다.
따라서 함수는 다음 분석 표현식으로 정의 할 수 있습니다.
이러한 기능을 인디케이터에 사용할 것입니다.
2. 멤버십 기능
어떤 식으로든 기술 인디케이터의 임무는 현재 시장 상태 (평탄한, 상승 추세, 하락 추세)를 결정하고 시장 진입/출구 신호를 생성하는 것입니다. 멤버십 기능의 도움으로 어떻게 할 수 있습니까? 충분히 쉽습니다.
먼저 경계 조건을 정의해야 합니다. 다음과 같은 경계 조건이 있습니다.«100 % 상승 추세»의 경우 매개 변수가 8, 0.08, SMA, Close, Envelopes 상단 경계와 함께 일반적인 가격 (H+L+C)/3을 기준으로 기간 2를 갖는 EMA의 교차점이 됩니다. 반면, «100% 하향 추세»의 경우 Envelopes 하단 경계가 있는 동일한 EMA의 교차점이 됩니다. 이러한 조건 사이에 있는 모든 것은 평평한 것으로 간주됩니다. 매개 변수가 32, 0.15, SMA, Close 인 봉투를 하나 더 추가해 보겠습니다.
결과적으로 두 개의 동일한 멤버십 기능을 얻게 됩니다. 두 기능이 모두 1이면 매수 신호가 활성화되고 두 기능이 각각 -1이면 매도 신호가 활성화됩니다. -1에서 1까지의 범위로 차트를 작성하는 것이 편리하므로 결과 차트는 두 함수 F(x)= (f1(x)+f2(x))/2의 산술 평균으로 얻어집니다.
이것이 차트에서 보이는 방식입니다.
이 경우 멤버십 기능은 다음과 같은 그래픽 표현을 갖습니다.
분석적으로 다음과 같이 작성할 수 있습니다.
,
여기서 a와 b는 각각 위쪽과 아래쪽 envelope 선이고 х는 EMA (2)의 값입니다.
함수가 정의되었으므로 이제 인디케이터 코드 작성으로 이동할 수 있습니다.
3. 프로그램 코드 생성
우선 무엇을 그리고 어떻게 그릴 것인지 정의해야 합니다.
멤버십 함수 계산 결과는 각각 빨간색과 파란색의 선으로 표시됩니다.
산술 평균은 제로 라인에서 히스토그램으로 표시되고 결과 함수 값에 따라 5 가지 색상 중 하나로 그려집니다.
DRAW_COLOR_HISTOGRAM 그리기 스타일을 사용합니다.
값이 1 또는 -1 인 히스토그램 바 위에 구매/종료 신호로 파란색 및 빨간색 직사각형을 그립니다.
이제 MetaEditor를 실행하고 시작할 시간입니다. 새로 만들기->사용자 지정 인디케이터->다음 ... "매개 변수" 필드를 채웁니다.
버퍼를 만듭니다.
"마침" 버튼을 클릭하면 소스 코드를 받고 개선을 시작합니다.
먼저 버퍼수를 정의해보겠습니다. 그중 7 개는 이미 마법사에 의해 생성되었습니다 (데이터 5 개, 색상 2 개). 5 개 더 필요합니다.
#property indicator_minimum -1.4 // Setting fractional values #property indicator_maximum 1.4 // Expert Advisors wizard ignores fractional parts for some reason #property indicator_buffers 12 // Changing the value from 7 to 12 (5 more buffers have been added)입력 매개 변수를 편집해보겠습니다.
input string txt1="----------"; input int Period_Fast=8; input ENUM_MA_METHOD Method_Fast = MODE_SMA; /*Smoothing method*/ //moving average smoothing method 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; /*Deviation parameter*/ 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; // Fast envelope int Envelopes_Slow; // Slow envelope int MA_Signal; // Signal line double Env_Fast_Up[]; // Fast envelope upper border double Env_Fast_Dn[]; // Fast envelope lower border double Env_Slow_Up[]; // Slow envelope upper border double Env_Slow_Dn[]; // Slow envelope lower border double Mov_Sign[]; // Signal line
이제 OnInit() 함수로 이동합니다.
몇 가지 아름다움을 추가해 보겠습니다. 인디케이터 이름을 지정하고 추가 소수점 0을 제거합니다.
IndicatorSetInteger(INDICATOR_DIGITS,1); // setting display accuracy, we do not need some outstanding accuracy values string name; // indicator 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); // All indicator buffers at first SetIndexBuffer(5,SignalBuffer2,INDICATOR_DATA); // as this is Color Histogram2, then it has 2 data buffers SetIndexBuffer(6,SignalColors,INDICATOR_COLOR_INDEX);// the color buffer comes next.
핸들 채우기:
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<x) F=1; // 100% uptrend else if (x<=a && x>=c) F=(1-2*(a-x)/(a-c));// Flat else if (x<c) F=-1; // 100% downtrend return (F); }
준비가 끝났습니다. 변수와 버퍼가 선언되고 핸들이 할당됩니다.
이제 OnCalculate() 기본 함수를 진행할 차례입니다.
먼저 필요한 인디케이터의 값을 중간 버퍼에 적어 보겠습니다. CopyBuffer() 함수 사용:
CopyBuffer(Envelopes_Fast, // Indicator handle UPPER_LINE, // Indicator buffer 0, // The point to start 0 - from the very beginning rates_total, // How many to be copied - All Env_Fast_Up); // The buffer the values are written in // - the rest are done in a similar way 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);
여기에 계산 최적화를 위한 코드를 추가해야 합니다 (마지막 바의 재계산만 수행됨).
// declaring start variable for storing the index of the bar, recalculation of the indicator buffers will be // carried out from. int start; if (prev_calculated==0) // in case no bars have been calculated { start = Period_Slow; // not all indicators have been calculated up to this value, therefore, there is no point in executing the code } else start=prev_calculated-1; for (int i=start;i<rates_total;i++) { // All remaining code will be written here }
코드가 많이 남지 않았습니다.
x, a, b 매개 변수 설정, 멤버십 함수 값 계산 수행 및 적절한 버퍼에 쓰기:double x = Mov_Sign[i]; // Signal // Setting the first membership function parameters: double a1 = Env_Fast_Up[i]; // Upper border double b1 = Env_Fast_Dn[i]; // setting the first membership function value and writing it to the buffer Rule1Buffer[i] = Fuzzy(x,a1,b1); // Setting the second membership function parameters: double a2 = Env_Slow_Up[i]; // Upper border double b2 = Env_Slow_Dn[i]; // setting the second membership function value and writing it to the buffer Rule2Buffer[i] = Fuzzy(x,a2,b2);
두 개의 표시선이 만들어집니다.
이제 결과값을 계산해 봅시다.
ResultBuffer[i] = (Rule1Buffer[i]+Rule2Buffer[i])/2;
그런 다음 히스토그램 바를 적절한 색상으로 칠해야 합니다. 5 가지 색상이 있으므로 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; }
"컴파일"을 클릭하고 짜잔!
결론
그 밖에 무엇을 추가 할 수 있습니까? 이 기사에서는 fuzzy logic에 대한 가장 기본적인 접근 방식을 다루었습니다.
여기에는 다양한 실험을 위한 충분한 공간이 있습니다. 예를 들어 다음 함수를 사용할 수 있습니다.
그것에 대한 분석적 표현을 작성하고 적절한 조건을 찾는 것이 어렵지 않을 것이라고 생각합니다.
행운을 빕니다!
MetaQuotes 소프트웨어 사를 통해 러시아어가 번역됨.
원본 기고글: https://www.mql5.com/ru/articles/178