English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
시계열 예측을 위한 ENCOG 머신 러닝 프레임워크와 함께 MetaTrader 5 지표 사용

시계열 예측을 위한 ENCOG 머신 러닝 프레임워크와 함께 MetaTrader 5 지표 사용

MetaTrader 5 | 4 8월 2021, 17:13
211 0
investeo
investeo

소개

이 글에서는 Heaton Research에서 개발한 고급 신경망 및 기계 학습 프레임워크인 ENCOG에 MetaTrader 5를 소개합니다. MetaTrader가 FANN, NeuroSolutions, Matlab 및 NeuroShell과 같은 기계 학습 기술을 사용할 수 있도록 하는 이전에 설명한 방법이 있습니다. ENCOG는 강력하고 잘 설계된 코드이기 때문에 보완적인 솔루션이 되기를 바랍니다.

내가 ENCOG를 선택한 이유는 무엇입니까? 몇 가지 이유가 있습니다.

  1. ENCOG는 다른 두 가지 상업 거래 소프트웨어 패키지에 사용됩니다. 하나는 C#을 기반으로 하고 두 번째는 JAVA를 기반으로 합니다. 이는 금융 시계열 데이터를 예측하기 위해 이미 테스트되었음을 ​​의미합니다. 
  2. ENCOG는 무료 오픈 소스 소프트웨어입니다. 신경망 내부에서 무슨 일이 일어나는지 보고 싶다면 소스 코드를 찾아볼 수 있습니다. 이것은 시계열 예측 문제의 일부를 이해하기 위해 실제로 한 것입니다. C#은 깨끗하고 이해하기 쉬운 프로그래밍 언어입니다.
  3. ENCOG는 매우 잘 문서화되어 있습니다. Heaton Research의 설립자인 Mr Heaton은 신경망, 기계 학습 및 ENCOG를 사용하여 미래 데이터 예측에 대한 무료 온라인 과정을 제공합니다. 저는 이 글을 쓰기 전에 그의 레슨을 살펴봤습니다. 그 수업들은 제가 인공신경망을 이해하는데 많은 도움을 주었습니다. 또한 Heaton Research 웹사이트에는 JAVA 및 C#으로 ENCOG 프로그래밍에 대한 전자책이 있습니다. 전체 ENCOG 문서는 온라인에서 사용 가능합니다.
  4. ENCOG는 죽은 프로젝트가 아닙니다. 이 글을 작성하는 시점에서 ENCOG 2.6은 아직 개발 중에 있습니다. ENCOG 3.0 로드맵이 최근 발표되었습니다.
  5. ENCOG는 견고합니다. 잘 설계되었으며 여러 CPU 코어와 멀티스레딩을 사용하여 신경망 계산 속도를 높일 수 있습니다. 코드의 일부가 OpenCL - GPU 지원 계산을 위해 이식되기 시작합니다.
  6. ECNOG 현재 지원되는 기능: 

기계 학습 유형

신경망 아키텍처

훈련 기법활성화 기능무작위화 기법
  • 범위 무작위화
  • 가우스 난수
  • 팬인
  • 응우옌 위드로

계획된 기능:

보시다시피 이것은 상당히 긴 기능 목록입니다.

이 소개 글은 Resilient Propagation(RPROP) 교육을 통해 피드포워드 신경망 아키텍처에 중점을 둡니다. 또한 시간적 시계열 예측을 위한 타임박싱 및 정규화와 같은 데이터 준비의 기본 사항을 다룹니다.

이 글의 기본 지식은 Heaton Research 웹 사이트에서 사용할 수 있는 자습서와 NinjaTrader의 금융 시계열 예측에 대한 최신 글을 기반으로 합니다. ENCOG는 JAVA 및 C# 기반입니다. 이전 작업인 관리되지 않는 내보내기를 사용하여 MQL5에 C# 코드 노출 없이는 이 문서를 작성할 수 없습니다. 이 솔루션을 통해 C# DLL을 Metatrader 5 표시기와 ENCOG 시계열 예측기 간의 브리지로 사용할 수 있습니다.


1. 이 솔루션을 통해 C# DLL을 Metatrader 5 표시기와 ENCOG 시계열 예측기 간의 브리지로 사용할 수 있습니다.

인공 신경망은 뇌의 신경망을 모방하려고 하는 인간 공학 알고리즘입니다.

다양한 유형의 신경 알고리즘을 사용할 수 있으며 다양한 신경망 아키텍처가 있습니다. 연구 분야는 너무 광범위하여 단일 유형의 신경망에 대한 전체 책이 있습니다. 이러한 세부 사항은 이 글의 범위를 벗어나므로 Heaton Research 자습서를 보거나 해당 주제에 대한 책을 읽는 것만 권장합니다. 저는 피드포워드 신경망의 입력과 출력에 집중하고 금융 시계열 예측의 실제 예를 설명하려고 합니다.

금융 시계열 예측을 시작하려면 신경망에 무엇을 제공해야 하고 그 대가로 무엇을 기대할 수 있는지 생각해야 합니다. 대부분의 추상적인 블랙박스 사고에서 우리는 주어진 증권의 계약에 대해 롱 또는 숏 포지션을 취하고 일정 시간 후에 거래를 종료함으로써 손익을 달성합니다.

유가 증권의 과거 가격과 기술 지표의 가치를 관찰함으로써 우리는 계약을 매매하고 우리의 결정이 동전을 던져서 내려지지 않도록 하기 위해 가격의 미래 감정이나 방향을 예측하려고 합니다. 상황은 아래 그림과 비슷하지 않습니다.

그림 1. 기술 지표를 사용한 금융 시계열 예측

그림 1. 기술 지표를 사용한 재무 시계열 예측 

우리는 인공 지능으로 이를 달성하기 위해 노력할 것입니다. 신경망은 지표 값을 인식하고 가격이 오르거나 내릴 가능성이 있는지 결정합니다. 우리는 그것을 어떻게 달성합니까? 피드포워드 신경망 아키텍처를 사용하여 금융 시계열을 예측할 것이기 때문에 아키텍처를 소개해야 한다고 생각합니다.

피드 포워드 신경망은 레이어로 그룹화된 뉴런으로 구성됩니다. 입력 뉴런을 포함하는 입력 레이어와 출력 뉴런을 포함하는 출력 레이어의 최소 2개의 레이어가 있어야 합니다. 입력 레이어와 출력 레이어 사이에 숨겨진 레이어가 있을 수도 있습니다. 입력 레이어는 단순히 이중 값의 배열로 생각할 수 있으며 출력 레이어는 이중 값의 배열을 형성하는 하나 이상의 뉴런으로 구성될 수 있습니다. 아래 그림을 참조하십시오.

 그림 2. 피드포워드 신경망 계층

그림 2. 피드포워드 신경망 레이어 

도면을 단순화하기 위해 뉴런 간의 연결은 그리지 않았습니다. 입력 계층의 각 뉴런은 은닉 계층의 뉴런에 연결됩니다. 은닉층의 각 뉴런은 출력층의 뉴런에 연결됩니다.

각 연결에는 가중치가 있으며 이중 값과 임계값이 있는 활성화 함수가 있으며 이 가중치는 뉴런을 활성화하고 정보를 다음 뉴런으로 전달하는 역할을 합니다. 이것이 '피드포워드' 네트워크라고 불리는 이유입니다. 활성화된 뉴런의 출력에 기반한 정보는 뉴런의 한 레이어에서 다른 레이어로 피드포워드됩니다. 피드 포워드 신경망에 대한 자세한 소개 동영상을 보려면 다음 링크를 방문하세요.

신경망 아키텍처와 그 메커니즘에 대해 배운 후에도 여전히 의아해할 수 있습니다.

주요 문제는 다음과 같습니다.

  1. 신경망에 어떤 데이터를 제공할까요?
  2. 어떻게 먹일까요?
  3. 신경망에 대한 입력 데이터를 준비하는 방법은 무엇입니까? 
  4. 신경망 아키텍처를 선택하는 방법은 무엇입니까? 얼마나 많은 입력 뉴런, 은닉 뉴런 및 출력 뉴런이 필요합니까?
  5. 네트워크를 훈련시키는 방법은 무엇입니까?
  6. 어떤 결과가 나올 것으로 예상합니까?

 

2. 신경망에 공급할 데이터

지표 출력을 기반으로 재무 예측을 처리하기 때문에 네트워크에 지표 출력 값을 제공해야 합니다. 이 글에서는 입력으로 Stochastic %K, Stochastic Slow %DWilliams %R을 선택했습니다.

그림 3. 예측에 사용되는 기술 지표

그림 3. 예측에 사용되는 기술 지표

지표의 값을 추출하기 위해 iStochastic iWPR MQL5 기능을 사용할 수 있습니다.

double StochKArr[], StochDArr[], WilliamsRArr[];

ArraySetAsSeries(StochKArr, true);   
ArraySetAsSeries(StochDArr, true);   
ArraySetAsSeries(WilliamsRArr, true);

int hStochastic = iStochastic(Symbol(), Period(), 8, 5, 5, MODE_EMA, STO_LOWHIGH);
int hWilliamsR = iWPR(Symbol(), Period(), 21);
   
CopyBuffer(hStochastic, 0, 0, bufSize, StochKArr);
CopyBuffer(hStochastic, 1, 0, bufSize, StochDArr);
CopyBuffer(hWilliamsR, 0, 0, bufSize, WilliamsRArr);

이 코드가 실행된 후 3개의 배열 StochKArr, StochDArr 및 WilliamsRArr은 표시기 출력 값으로 채워져야 합니다. 훈련 샘플 크기에 따라 최대 수천 개의 값이 될 수 있습니다. 이 두 지표는 교육 목적으로만 선택되었음을 기억하십시오.

예측에 적합하다고 생각되는 모든 지표로 실험하는 것이 좋습니다. 네트워크에 금과 유가를 제공하여 주가 지수를 예측하거나 상관 외환 쌍을 사용하여 다른 통화 쌍을 예측할 수 있습니다. 

 

3. 타임박싱 입력 데이터

여러 지표에서 입력 데이터를 수집한 후 신경망에 입력하기 전에 입력을 '타임박스'해야 합니다. 타임박싱은 네트워크에 대한 입력을 이동하는 데이터 조각으로 표시할 수 있는 기술입니다. 시간 축에서 앞으로 이동하는 입력 데이터의 이동 상자를 상상할 수 있습니다. 이 절차에는 기본적으로 두 단계가 포함됩니다.

1. 각 표시기 버퍼에서 입력 데이터를 수집합니다. 시작 위치에서 미래를 향해 INPUT_WINDOW 수의 요소를 복사해야 합니다. 입력창은 예측에 사용된 바의 수입니다. 

 그림 4. 표시기 버퍼에서 입력 창 데이터 수집

그림 4. 표시기 버퍼에서 입력 창 데이터 수집 

위의 예에서 볼 수 있듯이 INPUT_WINDOW는 4개의 바와 같고 요소를 I1 배열에 복사했습니다. I1[0]은 첫 번째 요소입니다. I1[3]은 마지막 요소입니다. 유사하게 데이터는 다른 표시기에서 INPUT_WINDOW 크기 배열로 복사되어야 합니다. 이 수치는 AS_SERIES 플래그가 true로 설정된 시계열 배열에 유효합니다. 

2. INPUT_WINDOW 배열을 신경망 입력 계층에 공급되는 하나의 배열로 결합합니다. 

그림 5. 타임박스 입력 윈도우 배열 

그림 5. 타임박스 입력 윈도우 배열

3개의 Indicator가 있는데, 처음에는 각 Indicator의 첫 번째 값을 취한 다음 각 Indicator의 두 번째 값을 취하여 위 그림과 같이 입력 창이 채워질 때까지 계속합니다. 지표 출력에서 ​​결합된 이러한 배열은 신경망의 입력 레이어에 공급될 수 있습니다. 새로운 바가 도착하면 데이터가 하나의 요소로 분할되고 전체 절차가 반복됩니다. 예측 데이터를 준비하는 방법에 대해 자세히 알아보려면 해당 주제에 대한 동영상을 시청하는 것도 좋습니다.

 

4. 입력 데이터 정규화

신경망을 효과적으로 만들려면 데이터를 정규화해야 합니다. 이것은 활성화 함수의 정확한 계산에 필요합니다. 정규화는 데이터를 0..1 또는 -1..1 범위로 변환하는 수학적 프로세스입니다. 정규화된 데이터는 비정규화될 수 있습니다. 즉, 다시 원래 범위로 변환됩니다.

신경망 출력을 사람이 읽을 수 있는 형식으로 디코딩하려면 비정규화가 필요합니다. 고맙게도 ENCOG는 정규화 및 비정규화를 처리하므로 구현할 필요가 없습니다. 작동 방식이 궁금하다면 다음 코드를 분석할 수 있습니다.

/**
         * Normalize the specified value.
         * @param value The value to normalize.
         * @return The normalized value.
         */
        public static double normalize(final int value) {
                return ((value - INPUT_LOW) 
                                / (INPUT_HIGH - INPUT_LOW))
                                * (OUTPUT_HIGH - OUTPUT_LOW) + OUTPUT_LOW;
        }
        
        /**
         * De-normalize the specified value.
         * @param value The value to denormalize.
         * @return The denormalized value.
         */
        public static double deNormalize(final double data) {
                double result = ((INPUT_LOW - INPUT_HIGH) * data - OUTPUT_HIGH
                                * INPUT_LOW + INPUT_HIGH * OUTPUT_LOW)
                                / (OUTPUT_LOW - OUTPUT_HIGH);
                return result;
        }

작동 방식이 궁금하다면 다음 코드를 분석할 수 있습니다

 

5. 네트워크 아키텍처 및 뉴런 수 선택

주제에 대한 초보자에게 올바른 네트워크 아키텍처를 선택하는 것은 어려운 부분입니다. 이 글에서는 피드포워드 신경망 아키텍처를 입력 계층, 은닉 계층 및 출력 계층의 세 가지 계층으로 제한합니다. 더 많은 수의 레이어를 자유롭게 실험할 수 있습니다.

입력 및 출력 레이어의 경우 필요한 뉴런 수를 정확하게 계산할 수 있습니다. 은닉층의 경우 순방향 선택 알고리즘을 사용하여 신경망 오류를 최소화하려고 합니다. 다른 방법을 사용하는 것이 좋습니다. 뉴런의 수를 계산하기 위한 몇 가지 유전 알고리즘이 있을 수 있습니다.

ENCOG에서 사용하는 또 다른 방법은 역방향 선택 알고리즘 또는 가지치기(pruning)라고 하며 기본적으로 레이어 간의 연결을 평가하고 가중치가 0인 연결이 없는 숨겨진 뉴런을 제거하는 것이므로 시도해 볼 수도 있습니다.

5.1. 입력 뉴런 레이어

타임박싱으로 인해 입력 레이어의 뉴런 수는 다음 바를 예측하는 데 사용되는 표시기 수 곱하기 바 수와 같아야 합니다. 3개의 표시기를 입력으로 사용하고 입력 창 크기가 6개의 바와 같으면 입력 레이어는 18개의 뉴런으로 구성됩니다. 입력 레이어에는 타임박싱으로 준비된 데이터가 제공됩니다.

5.2. 숨겨진 뉴런 레이어

은닉 네트워크의 수는 훈련된 신경망 성능을 기반으로 추정해야 합니다. 여러 은닉 뉴런에 대한 간단한 수학 방정식은 없습니다. 글을 작성하기 전에 여러 시행착오 접근 방식을 사용했으며 Heaton Research 웹 사이트에서 순방향 선택 알고리즘을 이해하는 데 도움이 되는 알고리즘을 찾았습니다.

그림 6. 은닉 뉴런 수에 대한 순방향 선택 알고리즘  

그림 6. 숨겨진 뉴런 수에 대한 순방향 선택 알고리즘 

5.3. 출력 뉴런 레이어

우리의 목적을 위해 출력 뉴런의 수는 우리가 예측하려는 바의 수입니다. 숨겨진 뉴런과 출력 뉴런의 수가 많을수록 네트워크를 훈련하는 데 시간이 더 오래 걸린다는 점을 기억하십시오. 이 글에서는 미래에 하나의 바를 예측하려고 하므로 출력 레이어는 하나의 뉴런으로 구성됩니다.

 

6. MetaTrader 5에서 ENCOG로 교육 데이터 내보내기

Encog는 신경망 훈련을 위해 CSV 파일을 허용합니다.

다른 거래 소프트웨어에서 ENCOG로 내보낸 파일 형식을 살펴보고 동일한 파일 형식을 교육용으로 준비하는 MQL5 스크립트를 구현했습니다. 처음에는 하나의 지표를 내보내고 나중에 여러 지표로 계속할 것입니다. 

데이터의 첫 번째 줄은 쉼표로 구분된 헤더입니다.

DATE,TIME,CLOSE,Indicator_Name1,Indicator_Name2,Indicator_Name3

처음 세 개의 열에는 날짜, 시간 및 종가 값이 포함되고 다음 열에는 지표 이름이 포함됩니다. 교육 파일의 다음 행에는 쉼표로 구분된 데이터가 포함되어야 하며 지표 값은 과학 형식으로 작성되어야 합니다.  

20110103,0000,0.93377000,-7.8970208860e-002

아래의 하나의 지표에 대해 미리 만들어진 스크립트를 준수하십시오.

//+------------------------------------------------------------------+
//|                                                ExportToEncog.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+

// Export Indicator values for NN training by ENCOG
extern string IndExportFileName = "mt5export.csv";
extern int  trainSize = 400;
extern int  maPeriod = 210;

MqlRates srcArr[];
double expBullsArr[];

void OnStart()
  {
//---
   ArraySetAsSeries(srcArr, true);   
   ArraySetAsSeries(expBullsArr, true);      
         
   int copied = CopyRates(Symbol(), Period(), 0, trainSize, srcArr);
   
   if (copied!=trainSize) { Print("Not enough data for " + Symbol()); return; }
   
   int hBullsPower = iBullsPower(Symbol(), Period(), maPeriod);
   
   CopyBuffer(hBullsPower, 0, 0, trainSize, expBullsArr);
   
   int hFile = FileOpen(IndExportFileName, FILE_CSV | FILE_ANSI | FILE_WRITE | FILE_REWRITE, ",", CP_ACP);
   
   FileWriteString(hFile, "DATE,TIME,CLOSE,BullsPower\n");
   
   Print("Exporting indicator data to " + IndExportFileName);
   
   for (int i=trainSize-1; i>=0; i--)
      {
         string candleDate = TimeToString(srcArr[i].time, TIME_DATE);
         StringReplace(candleDate,".","");
         string candleTime = TimeToString(srcArr[i].time, TIME_MINUTES);
         StringReplace(candleTime,":","");
         FileWrite(hFile, candleDate, candleTime, DoubleToString(srcArr[i].close), DoubleToString(expBullsArr[i], -10));
      }
      
   FileClose(hFile);   
     
   Print("Indicator data exported."); 
  }
//+------------------------------------------------------------------+

 훈련에 사용할 수 있는 결과 파일은 다음 출력과 같아야 합니다. 

DATE,TIME,CLOSE,BullsPower
20110103,0000,0.93377000,-7.8970208860e-002
20110104,0000,0.94780000,-6.4962292188e-002
20110105,0000,0.96571000,-4.7640374727e-002
20110106,0000,0.96527000,-4.4878854587e-002
20110107,0000,0.96697000,-4.6178012364e-002
20110110,0000,0.96772000,-4.2078647318e-002
20110111,0000,0.97359000,-3.6029181466e-002
20110112,0000,0.96645000,-3.8335729509e-002
20110113,0000,0.96416000,-3.7054869514e-002
20110114,0000,0.96320000,-4.4259373120e-002
20110117,0000,0.96503000,-4.4835729773e-002
20110118,0000,0.96340000,-4.6420936126e-002
20110119,0000,0.95585000,-4.6868984125e-002
20110120,0000,0.96723000,-4.2709941621e-002
20110121,0000,0.95810000,-4.1918330800e-002
20110124,0000,0.94873000,-4.7722659418e-002
20110125,0000,0.94230000,-5.7111591557e-002
20110126,0000,0.94282000,-6.2231529077e-002
20110127,0000,0.94603000,-5.9997865295e-002
20110128,0000,0.94165000,-6.0378312069e-002
20110131,0000,0.94414000,-6.2038328069e-002
20110201,0000,0.93531000,-6.0710334438e-002
20110202,0000,0.94034000,-6.1446445012e-002
20110203,0000,0.94586000,-5.2580791504e-002
20110204,0000,0.95496000,-4.5246755566e-002
20110207,0000,0.95730000,-4.4439392954e-002

StochasticWilliams' R 지표가 있는 원본 글 예제로 돌아가서 세 개의 쉼표로 구분된 열을 내보내야 하며, 각 열에는 별도의 지표 값이 있으므로 확장해야 합니다. 파일을 만들고 추가 버퍼를 추가합니다.

//+------------------------------------------------------------------+
//|                                                ExportToEncog.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+

// Export Indicator values for NN training by ENCOG
extern string IndExportFileName = "mt5export.csv";
extern int  trainSize = 2000;

MqlRates srcArr[];
double StochKArr[], StochDArr[], WilliamsRArr[];

void OnStart()
  {
//---
   ArraySetAsSeries(srcArr, true);   
   ArraySetAsSeries(StochKArr, true);   
   ArraySetAsSeries(StochDArr, true);   
   ArraySetAsSeries(WilliamsRArr, true);
         
   int copied = CopyRates(Symbol(), Period(), 0, trainSize, srcArr);
   
   if (copied!=trainSize) { Print("Not enough data for " + Symbol()); return; }
   
   int hStochastic = iStochastic(Symbol(), Period(), 8, 5, 5, MODE_EMA, STO_LOWHIGH);
   int hWilliamsR = iWPR(Symbol(), Period(), 21);
   
   
   CopyBuffer(hStochastic, 0, 0, trainSize, StochKArr);
   CopyBuffer(hStochastic, 1, 0, trainSize, StochDArr);
   CopyBuffer(hWilliamsR, 0, 0, trainSize, WilliamsRArr);
    
   int hFile = FileOpen(IndExportFileName, FILE_CSV | FILE_ANSI | FILE_WRITE | FILE_REWRITE, ",", CP_ACP);
   
   FileWriteString(hFile, "DATE,TIME,CLOSE,StochK,StochD,WilliamsR\n");
   
   Print("Exporting indicator data to " + IndExportFileName);
   
   for (int i=trainSize-1; i>=0; i--)
      {
         string candleDate = TimeToString(srcArr[i].time, TIME_DATE);
         StringReplace(candleDate,".","");
         string candleTime = TimeToString(srcArr[i].time, TIME_MINUTES);
         StringReplace(candleTime,":","");
         FileWrite(hFile, candleDate, candleTime, DoubleToString(srcArr[i].close), 
                                                 DoubleToString(StochKArr[i], -10),
                                                 DoubleToString(StochDArr[i], -10),
                                                 DoubleToString(WilliamsRArr[i], -10)
                                                 );
      }
      
   FileClose(hFile);   
     
   Print("Indicator data exported."); 
  }
//+------------------------------------------------------------------+

결과 파일에는 모든 표시기 값이 있어야 합니다.

DATE,TIME,CLOSE,StochK,StochD,WilliamsR
20030707,0000,1.37370000,7.1743119266e+001,7.2390220187e+001,-6.2189054726e-001
20030708,0000,1.36870000,7.5140977444e+001,7.3307139273e+001,-1.2500000000e+001
20030709,0000,1.35990000,7.3831775701e+001,7.3482018082e+001,-2.2780373832e+001
20030710,0000,1.36100000,7.1421933086e+001,7.2795323083e+001,-2.1495327103e+001
20030711,0000,1.37600000,7.5398313027e+001,7.3662986398e+001,-3.9719626168e+000
20030714,0000,1.37370000,7.0955352856e+001,7.2760441884e+001,-9.6153846154e+000
20030715,0000,1.38560000,7.4975891996e+001,7.3498925255e+001,-2.3890784983e+000
20030716,0000,1.37530000,7.5354107649e+001,7.4117319386e+001,-2.2322435175e+001
20030717,0000,1.36960000,7.1775345074e+001,7.3336661282e+001,-3.0429594272e+001
20030718,0000,1.36280000,5.8474576271e+001,6.8382632945e+001,-3.9778325123e+001
20030721,0000,1.35400000,4.3498596819e+001,6.0087954237e+001,-5.4946524064e+001
20030722,0000,1.36130000,2.9036761284e+001,4.9737556586e+001,-4.5187165775e+001
20030723,0000,1.34640000,1.6979405034e+001,3.8818172735e+001,-6.5989159892e+001
20030724,0000,1.34680000,1.0634573304e+001,2.9423639592e+001,-7.1555555556e+001
20030725,0000,1.34400000,9.0909090909e+000,2.2646062758e+001,-8.7500000000e+001
20030728,0000,1.34680000,1.2264922322e+001,1.9185682613e+001,-8.2705479452e+001
20030729,0000,1.35250000,1.4960629921e+001,1.7777331716e+001,-7.2945205479e+001
20030730,0000,1.36390000,2.7553336360e+001,2.1035999930e+001,-5.3979238754e+001
20030731,0000,1.36990000,4.3307839388e+001,2.8459946416e+001,-4.3598615917e+001
20030801,0000,1.36460000,5.6996412096e+001,3.7972101643e+001,-5.2768166090e+001
20030804,0000,1.34780000,5.7070193286e+001,4.4338132191e+001,-8.1833910035e+001
20030805,0000,1.34770000,5.3512705531e+001,4.7396323304e+001,-8.2006920415e+001
20030806,0000,1.35350000,4.4481132075e+001,4.6424592894e+001,-7.1972318339e+001
20030807,0000,1.35020000,3.3740028156e+001,4.2196404648e+001,-7.7681660900e+001
20030808,0000,1.35970000,3.0395426394e+001,3.8262745230e+001,-6.1245674740e+001
20030811,0000,1.35780000,3.4155781326e+001,3.6893757262e+001,-6.4532871972e+001
20030812,0000,1.36880000,4.3488943489e+001,3.9092152671e+001,-4.5501730104e+001
20030813,0000,1.36690000,5.1160443996e+001,4.3114916446e+001,-4.8788927336e+001
20030814,0000,1.36980000,6.2467599793e+001,4.9565810895e+001,-2.5629290618e+001
20030815,0000,1.37150000,6.9668246445e+001,5.6266622745e+001,-2.1739130435e+001
20030818,0000,1.38910000,7.9908906883e+001,6.4147384124e+001,-9.2819614711e+000

두 번째 예제를 수정하여 필요에 맞는 스크립트를 쉽게 생성할 수 있습니다.


7. 신경망 훈련

네트워크 교육은 이미 Heaton Research에서 C#으로 준비했습니다. ENCOG 2.6은 금융 시계열 예측의 기반이 되는 Encog.App.Quant 네임스페이스를 구현합니다. 교육 스크립트는 매우 유연하여 원하는 수의 입력 표시기로 쉽게 조정할 수 있습니다. DIRECTORY 상수에서 MetaTrader 5 디렉토리 위치만 변경해야 합니다.

네트워크 아키텍처 및 교육 매개변수는 다음 변수를 변경하여 쉽게 사용자 지정할 수 있습니다.

        /// <summary>
        /// The size of the input window.  This is the number of bars used to predict the next bar.
        /// </summary>
        public const int INPUT_WINDOW = 6;        

        /// <summary>
        /// The number of bars forward we are trying to predict.  This is usually just 1 bar.  The future indicator used in step 1 may
        /// well look more forward into the future. 
        /// </summary>
        public const int PREDICT_WINDOW = 1;

        /// <summary>
        /// The number of bars forward to look for the best result.
        /// </summary>
        public const int RESULT_WINDOW = 5;

        /// <summary>
        /// The number of neurons in the first hidden layer.
        /// </summary>
        public const int HIDDEN1_NEURONS = 12;

        /// <summary>
        /// The target error to train to.
        /// </summary>
        public const double TARGET_ERROR = 0.01;

코드는 매우 자명하므로 주의 깊게 읽는 것이 가장 좋습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Encog.App.Quant.Normalize;
using Encog.Util.CSV;
using Encog.App.Quant.Indicators;
using Encog.App.Quant.Indicators.Predictive;
using Encog.App.Quant.Temporal;
using Encog.Neural.NeuralData;
using Encog.Neural.Data.Basic;
using Encog.Util.Simple;
using Encog.Neural.Networks;
using Encog.Neural.Networks.Layers;
using Encog.Engine.Network.Activation;
using Encog.Persist;

namespace NetworkTrainer
{
    public class Program
    {
        /// <summary>
        /// The directory that all of the files will be stored in.
        /// </summary>
        public const String DIRECTORY = "d:\\mt5\\MQL5\\Files\\";

        /// <summary>
        /// The input file that starts the whole process.  This file should be downloaded from NinjaTrader using the EncogStreamWriter object.
        /// </summary>
        public const String STEP1_FILENAME = DIRECTORY + "mt5export.csv";

        /// <summary>
        /// We apply a predictive future indicator and generate a second file, with the additional predictive field added.
        /// </summary>
        public const String STEP2_FILENAME = DIRECTORY + "step2_future.csv";

        /// <summary>
        /// Next the entire file is normalized and stored into this file.
        /// </summary>
        public const String STEP3_FILENAME = DIRECTORY + "step3_norm.csv";

        /// <summary>
        /// The file is time-boxed to create training data.
        /// </summary>
        public const String STEP4_FILENAME = DIRECTORY + "step4_train.csv";

        /// <summary>
        /// Finally, the trained neural network is written to this file.
        /// </summary>
        public const String STEP5_FILENAME = DIRECTORY + "step5_network.eg";
       
        /// <summary>
        /// The size of the input window.  This is the number of bars used to predict the next bar.
        /// </summary>
        public const int INPUT_WINDOW = 6;        

        /// <summary>
        /// The number of bars forward we are trying to predict.  This is usually just 1 bar.  The future indicator used in step 1 may
        /// well look more forward into the future. 
        /// </summary>
        public const int PREDICT_WINDOW = 1;

        /// <summary>
        /// The number of bars forward to look for the best result.
        /// </summary>
        public const int RESULT_WINDOW = 5;

        /// <summary>
        /// The number of neurons in the first hidden layer.
        /// </summary>
        public const int HIDDEN1_NEURONS = 12;

        /// <summary>
        /// The target error to train to.
        /// </summary>
        public const double TARGET_ERROR = 0.01;

        static void Main(string[] args)
        {
            // Step 1: Create future indicators
            Console.WriteLine("Step 1: Analyze MT5 Export & Create Future Indicators");
            ProcessIndicators ind = new ProcessIndicators();
            ind.Analyze(STEP1_FILENAME, true, CSVFormat.DECIMAL_POINT);
            int externalIndicatorCount = ind.Columns.Count - 3;
            ind.AddColumn(new BestReturn(RESULT_WINDOW,true)); 
            ind.Process(STEP2_FILENAME);          
            Console.WriteLine("External indicators found: " + externalIndicatorCount);
            //Console.ReadKey();

            // Step 2: Normalize
            Console.WriteLine("Step 2: Create Future Indicators");
            EncogNormalize norm = new EncogNormalize();
            norm.Analyze(STEP2_FILENAME, true, CSVFormat.ENGLISH);
            norm.Stats[0].Action = NormalizationDesired.PassThrough; // Date
            norm.Stats[1].Action = NormalizationDesired.PassThrough; // Time
            
            norm.Stats[2].Action = NormalizationDesired.Normalize; // Close
            norm.Stats[3].Action = NormalizationDesired.Normalize; // Stoch K
            norm.Stats[4].Action = NormalizationDesired.Normalize; // Stoch Dd
            norm.Stats[5].Action = NormalizationDesired.Normalize; // WilliamsR
       
            norm.Stats[6].Action = NormalizationDesired.Normalize; // best return [RESULT_WINDOW]

            norm.Normalize(STEP3_FILENAME);

            // neuron counts
            int inputNeurons = INPUT_WINDOW * externalIndicatorCount;
            int outputNeurons = PREDICT_WINDOW;

            // Step 3: Time-box
            Console.WriteLine("Step 3: Timebox");
            //Console.ReadKey();
            TemporalWindow window = new TemporalWindow();
            window.Analyze(STEP3_FILENAME, true, CSVFormat.ENGLISH);
            window.InputWindow = INPUT_WINDOW;
            window.PredictWindow = PREDICT_WINDOW;
            int index = 0;
            window.Fields[index++].Action = TemporalType.Ignore; // date
            window.Fields[index++].Action = TemporalType.Ignore; // time
            window.Fields[index++].Action = TemporalType.Ignore; // close
            for(int i=0;i<externalIndicatorCount;i++)
                window.Fields[index++].Action = TemporalType.Input; // external indicators
            window.Fields[index++].Action = TemporalType.Predict; // PredictBestReturn

            window.Process(STEP4_FILENAME);

            // Step 4: Train neural network
            Console.WriteLine("Step 4: Train");
            Console.ReadKey();
            INeuralDataSet training = (BasicNeuralDataSet)EncogUtility.LoadCSV2Memory(STEP4_FILENAME, inputNeurons, 
                                                                                      outputNeurons, true, CSVFormat.ENGLISH);

            BasicNetwork network = new BasicNetwork();
            network.AddLayer(new BasicLayer(new ActivationTANH(), true, inputNeurons));
            network.AddLayer(new BasicLayer(new ActivationTANH(), true, HIDDEN1_NEURONS));
            network.AddLayer(new BasicLayer(new ActivationLinear(), true, outputNeurons));
            network.Structure.FinalizeStructure();
            network.Reset();

            //EncogUtility.TrainToError(network, training, TARGET_ERROR);
            EncogUtility.TrainConsole(network, training, 3);

            // Step 5: Save neural network and stats
            EncogMemoryCollection encog = new EncogMemoryCollection();
            encog.Add("network", network);
            encog.Add("stat", norm.Stats);
            encog.Save(STEP5_FILENAME);
            Console.ReadKey();
        }
    }
}

한 줄을 주석 처리하고 EncogUtility.TrainToError()에서 EncogUtility.TrainConsole()로 학습 함수를 변경했음을 알 수 있습니다.

EncogUtility.TrainConsole(network, training, 3);

TrainConsole 메소드는 네트워크를 훈련하는 데 걸리는 시간(분)을 지정합니다. 이 예에서는 3분 동안 네트워크를 훈련합니다. 네트워크의 복잡성과 훈련 데이터의 크기에 따라 네트워크를 훈련하는 데 몇 분, 몇 시간 또는 며칠이 걸릴 수 있습니다. Heaton Research 웹사이트의 오류 계산학습 알고리즘에 대해 자세히 알아보거나 해당 주제에 대한 다른 책을 읽는 것이 좋습니다.

EncogUtility.TrainToError() 메소드는 대상 네트워크 오류가 발생한 후 네트워크 교육을 중지합니다. EncongUtiliy.TrainConsole()에 주석을 달고 EncogUtility.TrainToError()의 주석을 제거하여 원래 예제에서와 같이 원하는 오류까지 네트워크를 훈련할 수 있습니다. 

EncogUtility.TrainToError(network, training, TARGET_ERROR);

뉴런의 수가 너무 적기 때문에 네트워크가 특정 오류에 대해 훈련되지 않는 경우가 있습니다.


8. 훈련된 신경망을 사용하여 MetaTrader 5 신경 지표 구축

훈련된 네트워크는 최고의 투자 수익을 예측하려고 시도하는 신경망 지표에서 사용할 수 있습니다.

MetaTrader 5의 ENCOG 신경 표시기는 두 부분으로 구성됩니다. 한 부분은 MQL5로 작성되었으며 기본적으로 네트워크가 훈련된 것과 동일한 표시기를 사용하고 네트워크에 입력 창 표시기 값을 제공합니다. 두 번째 부분은 C#으로 작성되었으며 입력 데이터를 타임박스 처리하고 신경망 출력을 MQL5로 반환합니다. C# 표시기 부분은 C# 코드를 MQL5에 노출에 대한 이전 글을 기반으로 합니다.

using System;
using System.Collections.Generic;
using System.Text;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
using Encog.Neural.Networks;
using Encog.Persist;
using Encog.App.Quant.Normalize;
using Encog.Neural.Data;
using Encog.Neural.Data.Basic;

namespace EncogNeuralIndicatorMT5DLL
{

    public class NeuralNET
    {
        private EncogMemoryCollection encog;
        public BasicNetwork network;
        public NormalizationStats stats;

        public NeuralNET(string nnPath)
        {
            initializeNN(nnPath);
        }

        public void initializeNN(string nnPath)
        {
            try
            {
                encog = new EncogMemoryCollection();
                encog.Load(nnPath);
                network = (BasicNetwork)encog.Find("network");
                stats = (NormalizationStats)encog.Find("stat");
            }
            catch (Exception e)
            {
                Console.WriteLine(e.StackTrace);
            }
        }
    };

   class UnmanagedExports
   {

      static NeuralNET neuralnet; 

      [DllExport("initializeTrainedNN", CallingConvention = CallingConvention.StdCall)]
      static int initializeTrainedNN([MarshalAs(UnmanagedType.LPWStr)]string nnPath)
      {
          neuralnet = new NeuralNET(nnPath);

          if (neuralnet.network != null) return 0;
          else return -1;
      }

      [DllExport("computeNNIndicator", CallingConvention = CallingConvention.StdCall)]
      public static int computeNNIndicator([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t1,
                                           [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t2,
                                           [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t3, 
                                           int len, 
                                           [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] double[] result,
                                           int rates_total)
      {
          INeuralData input = new BasicNeuralData(3 * len);
          
          int index = 0;
          for (int i = 0; i <len; i++)
          {
              input[index++] = neuralnet.stats[3].Normalize(t1[i]);
              input[index++] = neuralnet.stats[4].Normalize(t2[i]);
              input[index++] = neuralnet.stats[5].Normalize(t3[i]);
          }

          INeuralData output = neuralnet.network.Compute(input);
          double d = output[0];
          d = neuralnet.stats[6].DeNormalize(d);        
          result[rates_total-1]=d;

          return 0;
      }  
   }
}

3개 이외의 다른 수의 표시기를 사용하려면 필요에 맞게 computeNNIndicator() 메소드를 변경해야 합니다. 

 [DllExport("computeNNIndicator", CallingConvention = CallingConvention.StdCall)]
      public static int computeNNIndicator([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t1,
                                         [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t2,
                                         [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t3, 
                                         int len, 
                                         [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] double[] result,
                                         int rates_total)

이 경우 3개의 첫 번째 입력 매개변수는 표시기 입력 값을 포함하는 테이블이고, 네 번째 매개변수는 입력 창 길이입니다.

SizeParamIndex = 3은 입력 변수 개수가 0부터 증가하므로 입력 창 길이 변수를 가리킵니다. 다섯 번째 매개변수는 신경망 결과를 포함하는 테이블입니다. 

MQL5 표시기 부분은 C# EncogNNTrainDLL.dll을 가져오고 dll에서 내보낸 initializeTrainedNN() 및 computeNNIndicator() 함수를 사용해야 합니다.

//+------------------------------------------------------------------+
//|                                         NeuralEncogIndicator.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
#property indicator_separate_window

#property indicator_plots 1
#property indicator_buffers 1
#property indicator_color1 Blue
#property indicator_type1 DRAW_LINE
#property indicator_style1 STYLE_SOLID
#property indicator_width1  2

#import "EncogNNTrainDLL.dll"
   int initializeTrainedNN(string nnFile);
   int computeNNIndicator(double& ind1[], double& ind2[],double& ind3[], int size, double& result[], int rates);  
#import


int INPUT_WINDOW = 6;
int PREDICT_WINDOW = 1;

double ind1Arr[], ind2Arr[], ind3Arr[]; 
double neuralArr[];

int hStochastic;
int hWilliamsR;

int hNeuralMA;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0, neuralArr, INDICATOR_DATA);
   
   PlotIndexSetInteger(0, PLOT_SHIFT, 1);

   ArrayResize(ind1Arr, INPUT_WINDOW);
   ArrayResize(ind2Arr, INPUT_WINDOW);
   ArrayResize(ind3Arr, INPUT_WINDOW);
     
   ArrayInitialize(neuralArr, 0.0);
   
   ArraySetAsSeries(ind1Arr, true);   
   ArraySetAsSeries(ind2Arr, true);  
   ArraySetAsSeries(ind3Arr, true);
  
   ArraySetAsSeries(neuralArr, true);   
               
   hStochastic = iStochastic(NULL, 0, 8, 5, 5, MODE_EMA, STO_LOWHIGH);
   hWilliamsR = iWPR(NULL, 0, 21);
 
   Print(TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\Files\step5_network.eg");
   initializeTrainedNN(TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\Files\step5_network.eg");
      
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//---
   int calc_limit;
   
   if(prev_calculated==0) // First execution of the OnCalculate() function after the indicator start
        calc_limit=rates_total-34; 
   else calc_limit=rates_total-prev_calculated;
    
   ArrayResize(neuralArr, rates_total);
  
   for (int i=0; i<calc_limit; i++)     
   {
      CopyBuffer(hStochastic, 0, i, INPUT_WINDOW, ind1Arr);
      CopyBuffer(hStochastic, 1, i, INPUT_WINDOW, ind2Arr);
      CopyBuffer(hWilliamsR,  0, i, INPUT_WINDOW, ind3Arr);    
      
      computeNNIndicator(ind1Arr, ind2Arr, ind3Arr, INPUT_WINDOW, neuralArr, rates_total-i); 
   }
     
  //Print("neuralArr[0] = " + neuralArr[0]);
  
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

USDCHF 일일 데이터와 StochasticWilliams %R 지표에 대해 훈련된 지표 출력을 참조하십시오.

 그림 7. 신경 엔코그 표시기

그림 7. 신경 엔코그 표시기

표시기는 다음 바에 예상되는 최상의 투자 수익을 보여줍니다.

당신은 내가 표시기를 앞으로 한 바 이동한 것을 눈치채셨을 것입니다:

PlotIndexSetInteger(0, PLOT_SHIFT, 1);

이는 지표가 예측 지표임을 나타냅니다. 신경 지표를 구축했으므로 지표를 기반으로 Expert Advisor를 구축할 준비가 되었습니다.


9. 신경 지표 기반 Expert Advisor

Expert Advisor는 신경 지표 출력을 가져와 유가 증권을 매매할지 여부를 결정합니다. 제가 받은 첫인상은 지표가 0보다 높을 때 매수하고 0보다 낮을 때 매도해야 한다는 것이었습니다. 즉, 주어진 시간 창에서 최고의 수익률 예측이 양수일 때 매수하고 최고의 수익률 예측이 음수일 때 매도한다는 의미입니다.

몇 가지 초기 테스트 후 성능이 더 좋을 수 있음이 밝혀져 '강한 상승 추세' 및 '강한 하락 추세' 변수를 도입했습니다. 즉, 그 유명한 '추세는 당신의 친구입니다' 룰에 따라 우리가 강한 추세에 있을 때 거래를 종료할 이유가 없음을 의미합니다.

또한 Heaton Research 포럼에서 정지 손실 이동에 ATR을 사용하라는 조언을 받았으므로 MQL5 포럼에서 찾은 Chandelier ATR 표시기를 사용했습니다. 백테스팅하는 동안 실제로 지분 이득이 증가했습니다. 아래에 Expert Advisor의 소스 코드를 붙여넣습니다.

//+------------------------------------------------------------------+
//|                                           NeuralEncogAdvisor.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"

double neuralArr[];

double trend;
double Lots=0.3;

int INPUT_WINDOW=8;

int hNeural,hChandelier;

//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   ArrayResize(neuralArr,INPUT_WINDOW);
   ArraySetAsSeries(neuralArr,true);
   ArrayInitialize(neuralArr,0.0);

   hNeural=iCustom(Symbol(),Period(),"NeuralEncogIndicator");
   Print("hNeural = ",hNeural,"  error = ",GetLastError());

   if(hNeural<0)
     {
      Print("The creation of ENCOG indicator has failed: Runtime error =",GetLastError());
      //--- forced program termination
      return(-1);
     }
   else  Print("ENCOG indicator initialized");

   hChandelier=iCustom(Symbol(),Period(),"Chandelier");
   Print("hChandelier = ",hChandelier,"  error = ",GetLastError());

   if(hChandelier<0)
     {
      Print("The creation of Chandelier indicator has failed: Runtime error =",GetLastError());
      //--- forced program termination
      return(-1);
     }
   else  Print("Chandelier indicator initialized");
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   long tickCnt[1];
   int ticks=CopyTickVolume(Symbol(),0,0,1,tickCnt);
   if(tickCnt[0]==1)
     {
      if(!CopyBuffer(hNeural,0,0,INPUT_WINDOW,neuralArr)) { Print("Copy1 error"); return; }

      // Print("neuralArr[0] = "+neuralArr[0]+"neuralArr[1] = "+neuralArr[1]+"neuralArr[2] = "+neuralArr[2]);
      trend=0;

      if(neuralArr[0]<0 && neuralArr[1]>0) trend=-1;
      if(neuralArr[0]>0 && neuralArr[1]<0) trend=1;

      Trade();
     }
  }
//+------------------------------------------------------------------+
//| Tester function                                                  |
//+------------------------------------------------------------------+
double OnTester()
  {
//---

//---
   return(0.0);
  }
//+------------------------------------------------------------------+

void Trade()
  {
   double bufChandelierUP[2];
   double bufChandelierDN[2];

   double bufMA[2];

   ArraySetAsSeries(bufChandelierUP,true);
   ArraySetAsSeries(bufChandelierUP,true);

   ArraySetAsSeries(bufMA,true);

   CopyBuffer(hChandelier,0,0,2,bufChandelierUP);
   CopyBuffer(hChandelier,1,0,2,bufChandelierDN);

   MqlRates rates[];
   ArraySetAsSeries(rates,true);
   int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,3,rates);

   bool strong_uptrend=neuralArr[0]>0 && neuralArr[1]>0 && neuralArr[2]>0 &&
                      neuralArr[3]>0 && neuralArr[4]>0 && neuralArr[5]>0 &&
                       neuralArr[6]>0 && neuralArr[7]>0;
   bool strong_downtrend=neuralArr[0]<0 && neuralArr[1]<0 && neuralArr[2]<0 &&
                        neuralArr[3]<0 && neuralArr[4]<0 && neuralArr[5]<0 &&
                        neuralArr[6]<0 && neuralArr[7]<0;

   if(PositionSelect(_Symbol))
     {
      long type=PositionGetInteger(POSITION_TYPE);
      bool close=false;

      if((type==POSITION_TYPE_BUY) && (trend==-1))

         if(!(strong_uptrend) || (bufChandelierUP[0]==EMPTY_VALUE)) close=true;
      if((type==POSITION_TYPE_SELL) && (trend==1))
         if(!(strong_downtrend) || (bufChandelierDN[0]==EMPTY_VALUE))
            close=true;
      if(close)
        {
         CTrade trade;
         trade.PositionClose(_Symbol);
        }
      else // adjust s/l
        {
         CTrade trade;

         if(copied>0)
           {
            if(type==POSITION_TYPE_BUY)
              {
               if(bufChandelierUP[0]!=EMPTY_VALUE)
                  trade.PositionModify(Symbol(),bufChandelierUP[0],0.0);
              }
            if(type==POSITION_TYPE_SELL)
              {
               if(bufChandelierDN[0]!=EMPTY_VALUE)
                  trade.PositionModify(Symbol(),bufChandelierDN[0],0.0);
              }
           }
        }
     }

   if((trend!=0) && (!PositionSelect(_Symbol)))
     {
      CTrade trade;
      MqlTick tick;
      MqlRates rates[];
      ArraySetAsSeries(rates,true);
      int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,INPUT_WINDOW,rates);

      if(copied>0)
        {
         if(SymbolInfoTick(_Symbol,tick)==true)
           {
            if(trend>0)
              {
               trade.Buy(Lots,_Symbol,tick.ask);
               Print("Buy at "+tick.ask+" trend = "+trend+" neuralArr = "+neuralArr[0]);
              }
            if(trend<0)
              {
               trade.Sell(Lots,_Symbol,tick.bid);
               Print("Sell at "+tick.ask+" trend = "+trend+" neuralArr = "+neuralArr[0]);
              }
           }
        }
     }

  }
//+------------------------------------------------------------------+

Expert Advisor는 USDCHF 통화 D1 데이터에서 실행되었습니다. 데이터의 약 50%가 훈련 샘플에서 벗어났습니다.


10. Expert Advisor 백테스트 결과

아래에 백테스트 결과를 붙여넣습니다. 백테스트는 2000.01.01부터 2011.03.26까지 진행되었습니다.

그림 8. Neural Expert Advisor 백테스팅 결과

그림 8. Neural Expert Advisor 백테스팅 결과

그림 9. Neural Expert Advisor 잔액/주식 백테스팅 그래프

그림 9. Neural Expert Advisor 잔액/주식 백테스팅 그래프

이 성과는 다른 기간 및 기타 증권에 대해 완전히 다를 수 있습니다.

이 EA를 교육적인 것으로 취급하고 추가 연구를 위한 출발점으로 삼으십시오. 제 개인적인 견해는 네트워크를 더 강력하게 만들기 위해 특정 기간마다 네트워크를 재교육할 수 있다는 것입니다. 아마도 누군가는 이를 달성할 수 있는 좋은 방법을 찾았거나 이미 찾았을 것입니다. 아마도 신경 지표를 기반으로 매수/매도 예측을 하는 더 좋은 방법이 있을 것입니다. 저는 독자들에게 실험을 권합니다.


결론

다음 글에서 저는 ENCOG 머신 러닝 프레임워크를 사용하여 해당 지표를 기반으로 하는 신경 예측 지표 및 Expert Advisor를 구축하는 방법을 제시했습니다. 모든 소스 코드, 컴파일된 바이너리, DLL 및 훈련된 예시적인 네트워크가 글에 첨부되어 있습니다.


".NET의 이중 DLL 래핑" 때문에 Cloo.dll, encog-core-cs.dlllog4net.dll 파일은 클라이언트 터미널의 폴더에 있어야 합니다.
EncogNNTrainDLL.dll 파일은 \Terminal Data folder\MQL5\Libraries\ 폴더에 있어야 합니다.


MetaQuotes 소프트웨어 사를 통해 영어가 번역됨
원본 기고글: https://www.mql5.com/en/articles/252

파일 첨부됨 |
encogcsharp.zip (2202.77 KB)
files.zip (270.14 KB)
libraries.zip (321.62 KB)
experts.zip (1.56 KB)
scripts.zip (1.03 KB)
indicators.zip (2.24 KB)
C++ 템플릿의 대안으로 가짜 템플릿 사용 C++ 템플릿의 대안으로 가짜 템플릿 사용
이 글은 템플릿을 사용하지 않고 ihernet 프로그래밍 스타일을 유지하는 프로그래밍 방법을 설명합니다. 사용자 지정 방법을 사용하여 템플릿을 구현하는 방법에 대해 설명하고 지정된 템플릿을 기반으로 코드를 생성하기 위해 미리 만들어진 스크립트가 첨부되어 있습니다.
시장 가격 예측을 위한 범용 회귀 모델 시장 가격 예측을 위한 범용 회귀 모델
시장 가격은 다양한 경제적, 정치적, 심리적 요인에 따라 달라지는 수요와 공급 간의 안정적인 균형에서 형성됩니다. 이러한 요인들의 영향 요인과 성격의 차이로 인해 모든 구성 요소를 직접적으로 고려하기가 어렵습니다. 이 글은 정교한 회귀 모델을 기반으로 시장 가격을 예측하려는 시도를 설명합니다.
트레이딩 내 통계적 분산의 역할 트레이딩 내 통계적 분산의 역할
본 문서는 MQL5의 통계 확률 분포에 대해 논하고 이론적 통계 분산을 다루는 클래스들을 다룬 제 다른 문서의 논리적 후속작입니다. 이제 이론적 기반이 확보되었으므로 실제 데이터 셋으로 직접 이동하여 이 기반을 정보적으로 활용할 것을 제안합니다.
관리되지 않는 내보내기를 사용하여 MQL5에 C# 코드 노출 관리되지 않는 내보내기를 사용하여 MQL5에 C# 코드 노출
이 글에서는 MQL5 코드와 관리되는 C# 코드 간의 다양한 상호 작용 방법을 제시했습니다. 또한 C#에 대해 MQL5 구조를 마샬링하는 방법과 MQL5 스크립트에서 내보낸 DLL 함수를 호출하는 방법에 대한 몇 가지 예를 제공했습니다. 제공된 예제가 관리 코드에서 DLL을 작성하는 향후 연구의 기초가 될 수 있다고 생각합니다. 이 글은 또한 MetaTrader가 C#에서 이미 구현된 많은 라이브러리를 사용할 수 있는 기회를 제공합니다.