English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
또 다른 MQL5 OOP 클래스

또 다른 MQL5 OOP 클래스

MetaTrader 5 | 3 9월 2021, 09:47
168 0
laplacianlab
[삭제]

소개

실제로 작동하는 완전한 객체 지향 EA를 구축하는 것은 논리적 추론, 발산적 사고, 분석 및 종합 능력, 상상력 등 많은 기술을 모두 요구하는 도전적인 작업입니다. 우리가 해결해야 하는 자동 거래 시스템이 체스 게임이라면 거래 아이디어는 체스 전략이 될 것입니다. 그리고 전술을 통한 체스 전략의 실행은 기술 지표, 차트 수치, 기본 경제 아이디어 및 개념 공리를 사용하여 로봇을 프로그래밍하는 것입니다.

Raffaello Sanzio의 아테네 학파의 디테일

그림 1. Raffaello Sanzio의 아테네 학파의 디테일. 이 그림에서 철학자 플라톤과 아리스토텔레스가 심도 있게 토론하는 것을 볼 수 있습니다.
여기서 플라톤은 개념적 세계를 나타내고 아리스토텔레스는 경험주의적 세계를 나타냅니다.

저는 이 운동의 어려움을 알고 있습니다. OO EA는 프로그래밍하기가 매우 어렵지는 않지만 애플리케이션 개발 경험이 거의 없는 사람들에게 어느 정도의 어려움을 주는 것은 사실입니다. 다른 학문과 마찬가지로 이것은 경험 자체가 부족하기 때문입니다. 그래서 저는 당신이 이해할 것이라고 확신하는 구체적인 예를 통해 이 주제를 가르치려고 합니다. OOP 개념을 처리하는 데 여전히 불안함을 느끼더라도 낙담하지 마십시오. 예를 들어 처음 5개의 EA를 구현하고 나면 훨씬 더 쉽게 일을 찾을 수 있을 것입니다. 지금은 처음부터 아무것도 만들 필요가 없습니다. 여기에서 설명하는 내용만 이해하면 됩니다.

거래 시스템을 구상하고 실행하는 전체 과정은 여러 사람이 수행할 때 여러 면에서 단순화될 수 있지만 이러한 사실은 의사소통의 문제를 제기합니다. 내 말은 투자 전략을 구상하는 사람이 그들의 대화 상대인 프로그래머를 다루는 프로그래밍 개념을 다룰 필요가 없다는 뜻입니다. 그리고 MQL5 개발자는 처음에는 고객의 거래 전략의 몇 가지 중요한 측면을 이해하지 못할 수 있습니다.

이것은 스크럼, 테스트 주도 개발(TDD), 익스트림 프로그래밍( XP) 등 언어의 함정을 인식하는 것이 중요합니다. 그건 그렇고, Wikipedia는 "소프트웨어 엔지니어링의 소프트웨어 개발 방법론 또는 시스템 개발 방법론은 정보 시스템 개발 프로세스를 구성, 계획 및 제어하는 ​​데 사용되는 프레임워크"라고 말합니다.

우리는 성공적인 거래 아이디어를 신속하게 구상하고 실행할 수 있다고 가정할 것입니다. 또한 우리는 고객이 생각하는 거래 시스템이 이미 모두가 잘 정의하고 이해하는 반복적인 개발 프로세스의 끝에 있다고 가정할 수 있습니다. 당신이 원하는대로 말이죠. 그건 그렇고, 지금부터 이 텍스트에서 MQL5 프로그래밍 문서에서 사용할 수 있는 몇 가지 교육 문서를 참조하겠습니다. 당신이 이 연습을 성공적으로 수행하는 데 필요한 몇 가지 아이디어를 신속하게 확인하고 기억할 수 있게 말이죠. 준비가 되었나요?


1. 새로운 패러다임을 받아들이는 첫걸음


1.1. OOP가 Forex EA 프로그래밍에 좋은 이유는 무엇입니까?

아마도 이 시점에서 왜 이런 일을 해야 하는지 궁금할 것입니다. OOP를 강요받지 않는다는 점을 먼저 말씀드리겠습니다. 어쨌든 자동 거래 시스템 프로그래밍에 대한 지식을 한 단계 더 발전시키려면 OOP 담당자가 되는 것이 좋습니다.

절차적 프로그래밍이라고 하는 응용 프로그램을 개발하는 고전적인 방법에는 다음과 같은 단점이 있습니다.

  • 문제를 모델링하기 어렵게 만듭니다. 이 오래된 패러다임에서 주요 문제의 솔루션은 기능적 모듈, 즉 기능 및 절차에 의해 해결되는 더 간단한 하위 문제로 분할되도록 축소됩니다.
  • 코드를 재사용하기 어렵게 만들어 비용, 안정성, 유연성 및 유지 관리를 방해합니다.

새로운 객체 지향 스타일을 사용하면 코드 재사용이 더 쉬워집니다. 이건 매우 중요합니다! 많은 Expert들은 코드 재사용이 소프트웨어 개발의 대부분의 문제에 대한 진정한 해결책이라고 믿습니다.

이 시점에서 추상 데이터 유형(ADT)을 언급해야 합니다. OOP를 사용하면 ADT를 생성할 수 있습니다. ADT는 모든 프로그래밍 언어에 존재하는 데이터 유형의 전통적인 개념을 추상화한 것입니다. 주요 용도는 애플리케이션의 데이터 도메인을 편안하게 정의하는 것입니다. Include\Arrays\Array.mqh, Include\Arrays\List.mqhInclude\Arrays\Tree.mqh는 MQL5 추상 데이터 유형의 몇 가지 예입니다.

요컨대, 객체 지향 프로그래밍 패러다임은 코드 재사용, 안정성, 유연성 및 유지 관리 용이성의 이점을 누릴 수 있도록 개념적 수준에서 응용 프로그램을 설계하기를 원합니다.

1.2. 당신은 개념적 추론가입니까? UML이 구출에 나섭니다

UML에 대해 들어본 적이 있습니까? UML은 통합 모델링 언어의 약자입니다. 객체 지향 시스템을 설계하기 위한 그래픽 언어입니다. 우리 인간은 먼저 분석 단계에서 시스템을 생각한 다음 프로그래밍 언어로 코딩해야 합니다. 위에서 아래로 내려가는 것이 그나마 개발자들에게는 덜 미친 짓입니다. 그럼에도 불구하고, 분석가로서의 제 경험에 따르면 때때로 여러 가지 이유로 이것이 가능하지 않다고 말합니다. 앱은 매우 짧은 시간에 완료되어야 하고, 팀에 UML에 대한 지식을 신속하게 적용할 수 있는 사람이 없습니다. 아니면 팀 사람들이 UML의 일부분을 모를지도 모르는 일이죠.

제 생각에 UML은 편안하고 프로젝트를 둘러싼 상황이 괜찮다면 사용할 수 있는 좋은 분석 도구입니다. UML 주제를 탐색하는 데 관심이 있는 경우 UML 도구를 사용하여 Expert Advisor를 개발하는 방법을 읽어보세요. 글이 다소 압도적일 수는 있겠으나 전문 소프트웨어 엔지니어가 분석을 수행하는 방법에 대한 큰 그림을 얻는 데 도움이 됩니다. UML을 완전히 이해하려면 몇 주 과정을 완료해야 합니다! 지금은 UML이 무엇인지만 알아도 괜찮습니다. 제 경험에 따르면 이 분석 도구는 실제 세계에 존재하는 여러 상황으로 인해 모든 소프트웨어 프로젝트에서 항상 사용되는 것은 아닙니다.

UML 로고

그림 2. UML 로고.


1.3. Hello World! 첫 번째 OO 클래스

객체 지향 프로그래밍에 대한 완전한 초보자라면 먼저 MQL5 Reference에서 제공되는 OO에 대한 공식 문서인 MQL5 개체를 이용한 Expert Advisor 쓰기 - 기본 사항을 이해하기 위한 지향 프로그래밍 접근 방식을 읽어볼 것을 추천합니다. 이 글을 읽으면서 다른 자료로 정보를 꼭 보완하세요. 이제부터는 OOP를 이미 알고 있다고 가정하겠습니다. 그래야 당신이 MQL5에서 다음과 같은 Person 클래스의 고전적인 예를 쉽게 이해할 수 있을 테니까요.

//+------------------------------------------------------------------+
//| CPerson Class                                                    |
//+------------------------------------------------------------------+
class CPerson
  {
protected:
   string            m_first_name;
   string            m_surname;
   datetime          m_birth;

public:
   //--- Constructor and destructor methods
                     CPerson(void);
                    ~CPerson(void);
   //--- Getter methods
   string            GetFirstName(void);
   string            GetSurname(void);
   datetime          GetBirth(void);
   //--- Setter methods
   void              SetFirstName(string first_name);
   void              SetSurname(string surname);
   void              SetBirth(datetime birth);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CPerson::CPerson(void)
  {
   Alert("Hello world! I am run when an object of type CPerson is created!");
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CPerson::~CPerson(void)
  {
   Alert("Goodbye world! I am run when the object is destroyed!");
  }
//+------------------------------------------------------------------+
//| GetFirstName                                                     |
//+------------------------------------------------------------------+
string CPerson::GetFirstName(void)
  {
   return m_first_name;
  }
//+------------------------------------------------------------------+
//| GetSurname                                                       |
//+------------------------------------------------------------------+
string CPerson::GetSurname(void)
  {
   return m_surname;
  }
//+------------------------------------------------------------------+
//| GetBirth                                                         |
//+------------------------------------------------------------------+
datetime CPerson::GetBirth(void)
  {
   return m_birth;
  }
//+------------------------------------------------------------------+
//| SetFirstName                                                     |
//+------------------------------------------------------------------+
void CPerson::SetFirstName(string first_name)
  {
   m_first_name=first_name;
  }
//+------------------------------------------------------------------+
//| SetSurname                                                       |
//+------------------------------------------------------------------+
void CPerson::SetSurname(string surname)
  {
   m_surname=surname;
  }
//+------------------------------------------------------------------+
//| SetBirth                                                         |
//+------------------------------------------------------------------+
void CPerson::SetBirth(datetime birth)
  {
   m_birth=birth;
  }
//+------------------------------------------------------------------+

다음은 양질의 코드 작성에 집착하는 순수주의 개발자를 위한 것입니다. MQL5 프로그래밍 글코드 베이스에서 사용 가능한 다른 많은 소프트웨어와 달리, 위의 클래스는 MetaQuotes Software Corp에서 적용한 것과 동일한 프로그래밍 규칙을 사용합니다. MQL5 프레임워크를 코딩하기 위해 MetaQuotes처럼 코드를 작성하는 것이 좋습니다. 그건 그렇고, OOP MQL5 프로그램의 규칙 정보라는 제목의 스레드가 이 주제를 다룹니다.

간단히 말해서 Person.mqh 작성에 적용되는 몇 가지 중요한 규칙은 다음과 같습니다.

  • 클래스 이름 CPerson은 대문자 C로 시작합니다.
  • 메소드 이름은 카멜 케이스이며 대문자로 시작합니다(예: GetFirstName, SetSurname 등).
  • 보호 속성 이름 앞에는 m_ 접두사가 붙습니다(예: m_first_name, m_surnamem_born).
  • 예약어 this는 클래스 자체 내에서 클래스 멤버를 참조하는 데 사용되지 않습니다.

일부 MQL5 프레임워크 파일(예: Include\Arrays\Array.mqh, Include\Arrays\List.mqh, Include\Trade)을 살펴보십시오. \Trade.mqh에서 원래 MQL5 코드가 어떻게 작성되었는지 확인하세요.


2. 첫 번째 객체 지향 EA를 프로그래밍해봅시다


2.1. 거래 시스템의 아이디어

우리의 거래 아이디어는 간단합니다. "변동성 시장의 단기 추세는 거의 무작위입니다." 그게 다입니다. 이것은 어떤 상황에서 여러 Expert에 의해 관찰되었습니다. 이 가설이 사실이라면 Forex 로봇은 필연적으로 작동해야 합니다. 차트의 임의의 지점이 주어지면 다음 움직임은 분명히 위아래로 갈 수 있지만 우리는 그걸 알 수 없습니다. 문제는 설정된 SL과 TP 수준 간의 차이가 충분히 작으면 그 차이가 절대적으로 중요하지 않으므로 수학적 기대치에 도달했다는 것입니다. 이 시스템은 수학적 기대치를 작동하게 할 것입니다. 이 글에서 EA의 코드를 얻고 백테스트를 실행하면 매우 간단한 자금 관리 정책이 필요하다는 것을 알 수 있습니다.


2.2. 로봇의 OOP 스켈레톤

이 섹션에서는 객체 지향 프로그래밍이 요구하는 추상적인 추론을 통해 위의 전략을 개발합니다. 그렇다면 EA를 마치 살아있는 생물처럼 생각하는 것은 어떨까요? 이 비전에 따라 Forex 기계는 세 가지 주요 부분으로 구성될 수 있습니다. 두뇌, 진화라고 하는 것, 차트입니다.

두뇌는 ROM(읽기 전용 메모리)과 같은 작동에 필요한 데이터를 포함하는 로봇의 일부입니다. 차트는 로봇이 작동하는 그래픽을 모방한 정보 조각입니다. 마지막으로 소위 진화는 주어진 순간의 로봇 상태, 수행된 작업의 이력 등과 같은 시간적 정보를 포함하는 데이터 조각입니다. 마치 우리가 건강 부문을 위한 앱을 개발해야 하기 때문에 프랑켄슈타인과 같은 장기를 통해 인간을 디자인하는 것과 같습니다. 이러한 맥락에서 각 기관은 전체의 다른 부분과 관련된 고유한 의미 개념입니다.

우선 사용자 정의 항목을 저장할 MQL5\Include\Mine 폴더를 생성하겠습니다. 이것은 코드를 정리하기 위한 아이디어일 뿐입니다. 개발 과정에서 이 작업을 수행할 수 있다는 것을 아는 것이 좋지만 물론 강제로 수행해야 하는 것은 아닙니다. 그런 다음 우리가 생성한 열거형을 저장하기 위해 MQL5\Include\Mine\Enums.mqh 파일을 생성합니다.

//+------------------------------------------------------------------+
//| Status enumeration                                               |
//+------------------------------------------------------------------+
enum ENUM_STATUS_EA
  {
   BUY,
   SELL,
   DO_NOTHING
  };
//+------------------------------------------------------------------+
//| Lifetime enumeration                                             |
//+------------------------------------------------------------------+
enum ENUM_LIFE_EA
  {
   HOUR,
   DAY,
   WEEK,
   MONTH,
   YEAR
  };
//+------------------------------------------------------------------+

다음으로 ExpertSimpleRandom.mq5라는 이름의 EA 배아를 만들 차례입니다! 따라서 MQL5\Experts\SimpleRandom 폴더를 만든 다음 ExpertSimpleRandom.mq5 파일 안에 다음 코드를 만드십시오.

//+------------------------------------------------------------------+
//|                                           ExpertSimpleRandom.mq5 |
//|                               Copyright © 2013, Jordi Bassagañas |
//+------------------------------------------------------------------+

#property copyright     "Copyright © 2013, laplacianlab"
#property link          "https://www.mql5.com/ko/articles"
#property version       "1.00"

#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\PositionInfo.mqh>
#include <Indicators\Indicators.mqh>
#include <Mine\Enums.mqh>
#include <..\Experts\SimpleRandom\CSimpleRandom.mqh>

input int               StopLoss;
input int               TakeProfit;
input double            LotSize;
input ENUM_LIFE_EA      TimeLife;

MqlTick tick;
CSimpleRandom *SR=new CSimpleRandom(StopLoss,TakeProfit,LotSize,TimeLife);
//+------------------------------------------------------------------+
//| Initialization function                                          |
//+------------------------------------------------------------------+
int OnInit(void)
  {
   SR.Init();
   return(0);
  }
//+------------------------------------------------------------------+
//| Deinitialization function                                        |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   SR.Deinit();
   delete(SR);
  }
//+------------------------------------------------------------------+
//| OnTick event function                                            |
//+------------------------------------------------------------------+
void OnTick()
  {
   SymbolInfoTick(_Symbol,tick);
   SR.Go(tick.ask,tick.bid);
  }
//+------------------------------------------------------------------+

이것은 가능한 많은 방법 중 하나일 뿐입니다. 이 모든 것은 기본적으로 MQL5에서 OOP가 작동하는 방식을 설명하기 위한 것입니다. 보시다시피 Expert Advisor의 기본 클래스 이름은 CSimpleRandom.mqh입니다. MQL5\Experts\SimpleRandom\CSimpleRandom.mqh에 저장하십시오.

//+------------------------------------------------------------------+
//|                                           ExpertSimpleRandom.mq5 |
//|                               Copyright © 2013, Jordi Bassagañas |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
#include <Mine\Enums.mqh>
#include <..\Experts\SimpleRandom\CBrain.mqh>
#include <..\Experts\SimpleRandom\CEvolution.mqh>
#include <..\Experts\SimpleRandom\CGraphic.mqh>
//+------------------------------------------------------------------+
//| CSimpleRandom Class                                              |
//+------------------------------------------------------------------+
class CSimpleRandom
  {
protected:
   CBrain           *m_brain;
   CEvolution       *m_evolution;
   CGraphic         *m_graphic;
   CTrade           *m_trade;
   CPositionInfo    *m_positionInfo;
public:
   //--- Constructor and destructor methods
                     CSimpleRandom(int stop_loss,int take_profit,double lot_size,ENUM_LIFE_EA time_life);
                    ~CSimpleRandom(void);
   //--- Getter methods
   CBrain           *GetBrain(void);
   CEvolution       *GetEvolution(void);
   CGraphic         *GetGraphic(void);
   CTrade           *GetTrade(void);
   CPositionInfo    *GetPositionInfo(void);
   //--- Specific methods of CSimpleRandom
   bool              Init();
   void              Deinit(void);
   bool              Go(double ask,double bid);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CSimpleRandom::CSimpleRandom(int stop_loss,int take_profit,double lot_size,ENUM_LIFE_EA time_life)
  {
   int lifeInSeconds;

   switch(time_life)
     {
      case HOUR:

         lifeInSeconds=3600;

         break;

      case DAY:

         lifeInSeconds=86400;

         break;

      case WEEK:

         lifeInSeconds=604800;

         break;

      case MONTH:

         lifeInSeconds=2592000;

         break;

         // One year

      default:

         lifeInSeconds=31536000;

         break;
     }

   m_brain=new CBrain(TimeLocal(),TimeLocal()+lifeInSeconds,lot_size,stop_loss,take_profit);
   m_evolution=new CEvolution(DO_NOTHING);
   m_graphic=new CGraphic(_Symbol);
   m_trade=new CTrade();
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CSimpleRandom::~CSimpleRandom(void)
  {
   delete(m_brain);
   delete(m_evolution);
   delete(m_graphic);
   delete(m_trade);
  }
//+------------------------------------------------------------------+
//| GetBrain                                                         |
//+------------------------------------------------------------------+
CBrain *CSimpleRandom::GetBrain(void)
  {
   return m_brain;
  }
//+------------------------------------------------------------------+
//| GetBrain                                                         |
//+------------------------------------------------------------------+
CEvolution *CSimpleRandom::GetEvolution(void)
  {
   return m_evolution;
  }
//+------------------------------------------------------------------+
//| GetGraphic                                                       |
//+------------------------------------------------------------------+
CGraphic *CSimpleRandom::GetGraphic(void)
  {
   return m_graphic;
  }
//+------------------------------------------------------------------+
//| GetTrade                                                         |
//+------------------------------------------------------------------+
CTrade *CSimpleRandom::GetTrade(void)
  {
   return m_trade;
  }
//+------------------------------------------------------------------+
//| GetPositionInfo                                                  |
//+------------------------------------------------------------------+
CPositionInfo *CSimpleRandom::GetPositionInfo(void)
  {
   return m_positionInfo;
  }
//+------------------------------------------------------------------+
//| CSimpleRandom initialization                                     |
//+------------------------------------------------------------------+
bool CSimpleRandom::Init(void)
  {
// Initialization logic here...
   return true;
  }
//+------------------------------------------------------------------+
//| CSimpleRandom deinitialization                                   |
//+------------------------------------------------------------------+
void CSimpleRandom::Deinit(void)
  {
// Deinitialization logic here...
   delete(m_brain);
   delete(m_evolution);
   delete(m_graphic);
   delete(m_trade);
  }
//+------------------------------------------------------------------+
//| CSimpleRandom Go                                                 |
//+------------------------------------------------------------------+
bool CSimpleRandom::Go(double ask,double bid)
  {
   double tp;
   double sl;

   int coin=m_brain.GetRandomNumber(0,1);

// Is there any open position?     

   if(!m_positionInfo.Select(_Symbol))
     {
      // If not, we open one

      if(coin==0)
        {
         GetEvolution().SetStatus(BUY);
        }
      else
        {
         GetEvolution().SetStatus(SELL);
        }
     }

// If so, let it work the mathematical expectation.

   else GetEvolution().SetStatus(DO_NOTHING);

   switch(GetEvolution().GetStatus())
     {
      case BUY:

         tp = ask + m_brain.GetTakeProfit() * _Point;
         sl = bid - m_brain.GetStopLoss() * _Point;

         GetTrade().PositionOpen(_Symbol,ORDER_TYPE_BUY,m_brain.GetSize(),ask,sl,tp);

         break;

      case SELL:

         sl = ask + m_brain.GetStopLoss() * _Point;
         tp = bid - m_brain.GetTakeProfit() * _Point;

         GetTrade().PositionOpen(_Symbol,ORDER_TYPE_SELL,m_brain.GetSize(),bid,sl,tp);

         break;

      case DO_NOTHING:

         // Nothing...

         break;
     }

// If there is some error we return false, for now we always return true  

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


2.3. 복합 유형의 개체에 CSimpleRandom 바인딩

CBrain, CEvolutionCGraphic 유형의 사용자 정의 개체가 CSimpleRandom에 어떻게 연결되어 있는지 확인하십시오.

먼저 해당 보호 속성을 정의합니다.

protected:
   CBrain           *m_brain;
   CEvolution       *m_evolution;
   CGraphic         *m_graphic; 

그리고 생성자 내부에서 해당 개체를 인스턴스화한 직후:

m_brain=new CBrain(TimeLocal(), TimeLocal() + lifeInSeconds, lot_size, stop_loss, take_profit);         
m_evolution=new CEvolution(DO_NOTHING);      
m_graphic=new CGraphic(_Symbol);

우리가 하는 일은 공식 문서가 개체 포인터에서 설명하는 것처럼 복잡한 유형의 개체를 동적으로 생성하는 것입니다. 이 체계를 사용하면 CSimpleRandom에서 직접 CBrain, CEvolutionCGraphic의 기능에 액세스할 수 있습니다. 예를 들어 ExpertSimpleRandom.mq5에서 다음 코드를 실행할 수 있습니다.

//+------------------------------------------------------------------+
//| OnTick event function                                            |
//+------------------------------------------------------------------+
void OnTick()
   {              
      // ...
      
      int randNumber=SR.GetBrain().GetRandomNumber(4, 8);

      // ...          
  }

이제 이 섹션을 마무리하기 위해 CBrain, CEvolutionCGraphic 코드를 작성합니다. SimpleRandom을 백테스트하는 데 꼭 필요하지 않기 때문에 코딩되지 않은 부분이 있다는 점에 유의하십시오. 이 클래스의 누락된 부분을 코딩하는 것은 연습으로 남겨두고 원하는 대로 자유롭게 개발하십시오. 예를 들어, m_death는 실제로 사용되지 않지만 그 뒤에 숨어 있는 아이디어는 로봇이 활동을 완료할 날짜를 처음부터 알고 있다는 것입니다.

//+------------------------------------------------------------------+
//|                                               ExpertSimpleRandom |
//|                               Copyright © 2013, Jordi Bassagaсas |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| CBrain Class                                                     |
//+------------------------------------------------------------------+
class CBrain
  {
protected:
   ENUM_TIMEFRAMES   m_period;               // period must always be initialized to PERIOD_M1 to fit the system's idea
   datetime          m_birth;               // The datetime in which the robot is initialized for the first time
   datetime          m_death;               // The datetime in which the robot will die
   double            m_size;                // The size of the positions
   int               m_stopLoss;            // Stop loss
   int               m_takeProfit;          // Take profit

public:
   //--- Constructor and destructor methods
                     CBrain(datetime birth,datetime death,double size,int stopLoss,int takeProfit);
                    ~CBrain(void);
   //--- Getter methods
   datetime          GetBirth(void);
   datetime          GetDeath(void);
   double            GetSize(void);
   int               GetStopLoss(void);
   int               GetTakeProfit(void);
   //--- Setter methods
   void              SetBirth(datetime birth);
   void              SetDeath(datetime death);
   void              SetSize(double size);
   void              SetStopLoss(int stopLoss);
   void              SetTakeProfit(int takeProfit);
   //--- Brain specific logic
   int               GetRandomNumber(int a,int b);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CBrain::CBrain(datetime birth,datetime death,double size,int stopLoss,int takeProfit)
  {
   MathSrand(GetTickCount());

   m_period=PERIOD_M1;
   m_birth=birth;
   m_death=death;
   m_size=size;
   m_stopLoss=stopLoss;
   m_takeProfit=takeProfit;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CBrain::~CBrain(void)
  {
  }
//+------------------------------------------------------------------+
//| GetBirth                                                         |
//+------------------------------------------------------------------+
datetime CBrain::GetBirth(void)
  {
   return m_birth;
  }
//+------------------------------------------------------------------+
//| GetDeath                                                         |
//+------------------------------------------------------------------+
datetime CBrain::GetDeath(void)
  {
   return m_death;
  }
//+------------------------------------------------------------------+
//| GetSize                                                          |
//+------------------------------------------------------------------+
double CBrain::GetSize(void)
  {
   return m_size;
  }
//+------------------------------------------------------------------+
//| GetStopLoss                                                      |
//+------------------------------------------------------------------+
int CBrain::GetStopLoss(void)
  {
   return m_stopLoss;
  }
//+------------------------------------------------------------------+
//| GetTakeProfit                                                    |
//+------------------------------------------------------------------+
int CBrain::GetTakeProfit(void)
  {
   return m_takeProfit;
  }
//+------------------------------------------------------------------+
//| SetBirth                                                         |
//+------------------------------------------------------------------+
void CBrain::SetBirth(datetime birth)
  {
   m_birth=birth;
  }
//+------------------------------------------------------------------+
//| SetDeath                                                         |
//+------------------------------------------------------------------+
void CBrain::SetDeath(datetime death)
  {
   m_death=death;
  }
//+------------------------------------------------------------------+
//| SetSize                                                          |
//+------------------------------------------------------------------+
void CBrain::SetSize(double size)
  {
   m_size=size;
  }
//+------------------------------------------------------------------+
//| SetStopLoss                                                      |
//+------------------------------------------------------------------+
void CBrain::SetStopLoss(int stopLoss)
  {
   m_stopLoss=stopLoss;
  }
//+------------------------------------------------------------------+
//| SetTakeProfit                                                    |
//+------------------------------------------------------------------+
void CBrain::SetTakeProfit(int takeProfit)
  {
   m_takeProfit=takeProfit;
  }
//+------------------------------------------------------------------+
//| GetRandomNumber                                                  |
//+------------------------------------------------------------------+
int CBrain::GetRandomNumber(int a,int b)
  {
   return(a+(MathRand()%(b-a+1)));
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|                                               ExpertSimpleRandom |
//|                               Copyright © 2013, Jordi Bassagaсas |
//+------------------------------------------------------------------+
#include <Indicators\Indicators.mqh>
#include <Mine\Enums.mqh>
//+------------------------------------------------------------------+
//| CEvolution Class                                                 |
//+------------------------------------------------------------------+
class CEvolution
  {
protected:
   ENUM_STATUS_EA    m_status;            // The current EA's status
   CArrayObj*        m_operations;        // History of the operations performed by the EA

public:
   //--- Constructor and destructor methods
                     CEvolution(ENUM_STATUS_EA status);
                    ~CEvolution(void);
   //--- Getter methods
   ENUM_STATUS_EA    GetStatus(void);
   CArrayObj        *GetOperations(void);
   //--- Setter methods
   void              SetStatus(ENUM_STATUS_EA status);
   void              SetOperation(CObject *operation);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CEvolution::CEvolution(ENUM_STATUS_EA status)
  {
   m_status=status;
   m_operations=new CArrayObj;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CEvolution::~CEvolution(void)
  {
   delete(m_operations);
  }
//+------------------------------------------------------------------+
//| GetStatus                                                        |
//+------------------------------------------------------------------+
ENUM_STATUS_EA CEvolution::GetStatus(void)
  {
   return m_status;
  }
//+------------------------------------------------------------------+
//| GetOperations                                                    |
//+------------------------------------------------------------------+
CArrayObj *CEvolution::GetOperations(void)
  {
   return m_operations;
  }
//+------------------------------------------------------------------+
//| SetStatus                                                        |
//+------------------------------------------------------------------+
void CEvolution::SetStatus(ENUM_STATUS_EA status)
  {
   m_status=status;
  }
//+------------------------------------------------------------------+
//| SetOperation                                                     |
//+------------------------------------------------------------------+
void CEvolution::SetOperation(CObject *operation)
  {
   m_operations.Add(operation);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|                                           ExpertSimpleRandom.mq5 |
//|                               Copyright © 2013, Jordi Bassagaсas |
//+------------------------------------------------------------------+
#include <Trade\SymbolInfo.mqh>
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//| CGrapic Class                                                    |
//+------------------------------------------------------------------+
class CGraphic
  {
protected:
   ENUM_TIMEFRAMES   m_period;            // Graphic's timeframe
   string            m_pair;              // Graphic's pair
   CSymbolInfo*      m_symbol;            // CSymbolInfo object
   CArrayObj*        m_bars;              // Array of bars

public:
   //--- Constructor and destructor methods
                     CGraphic(string pair);
                    ~CGraphic(void);
   //--- Getter methods
   string            GetPair(void);
   CSymbolInfo      *GetSymbol(void);
   CArrayObj        *GetBars(void);
   //--- Setter methods
   void              SetPair(string pair);
   void              SetSymbol(CSymbolInfo *symbol);
   void              SetBar(CObject *bar);
  };
//+------------------------------------------------------------------+
//| Constuctor                                                       |
//+------------------------------------------------------------------+
CGraphic::CGraphic(string pair)
  {
   m_period=PERIOD_M1;
   m_pair=pair;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CGraphic::~CGraphic(void)
  {
  }
//+------------------------------------------------------------------+
//| GetPair                                                          |
//+------------------------------------------------------------------+
string CGraphic::GetPair(void)
  {
   return m_pair;
  }
//+------------------------------------------------------------------+
//| GetSymbol                                                        |
//+------------------------------------------------------------------+
CSymbolInfo *CGraphic::GetSymbol(void)
  {
   return m_symbol;
  }
//+------------------------------------------------------------------+
//| GetBars                                                          |
//+------------------------------------------------------------------+
CArrayObj *CGraphic::GetBars(void)
  {
   return m_bars;
  }
//+------------------------------------------------------------------+
//| SetPair                                                          |
//+------------------------------------------------------------------+
void CGraphic::SetPair(string pair)
  {
   m_pair=pair;
  }
//+------------------------------------------------------------------+
//| SetSymbol                                                        |
//+------------------------------------------------------------------+
void CGraphic::SetSymbol(CSymbolInfo *symbol)
  {
   m_symbol=symbol;
  }
//+------------------------------------------------------------------+
//| SetBar                                                           |
//+------------------------------------------------------------------+
void CGraphic::SetBar(CObject *bar)
  {
   m_bars.Add(bar);
  }
//+------------------------------------------------------------------+

3. Backtesting ExpertSimpleRandom.mq5

이 무작위 거래 시스템은 예상대로 특정 손절매 및 이익 수준에 대해서만 유효한 것으로 입증되었습니다. 물론 이러한 승자 SL/TP 간격은 모든 기호에 대해 동일하지 않습니다. 이는 모든 기호가 주어진 시간에 고유한 성격을 나타내기 때문입니다. 즉, 다른 말로 하면 모든 통화 쌍이 나머지에 대해 다르게 움직이기 때문입니다. 따라서 실제 환경에서 ExpertSimpleRandom.mq5를 실행하기 전에 백테스팅에서 이러한 수준을 먼저 식별하십시오.

이 글에서 드러난 아이디어가 승자처럼 보이는 몇 가지 샘플 데이터를 공유합니다. 이것은 MetaTrader 5 Strategy Tester에서 ExpertSimpleRandom.mq5를 여러 번 실행한 후에 추론할 수 있습니다.

2012년 1월 EURUSD에 대한 일부 승자 입력은 다음과 같습니다.

  • 손절매: 400
  • 이익실현: 600
  • 랏 크기: 0.01
  • TimeLife: MONTH

실행 번호 1:

EURUSD, 2012년 1월

실행 번호 2:

EURUSD, 2012년 1월

Run number 3:

EURUSD, 2012년 1월


결론

우리는 자동화된 거래 시스템에 객체 지향 프로그래밍을 적용하는 방법을 배웠습니다. 이를 위해 먼저 기계적 거래 전략을 정의해야 했습니다. 우리의 거래 아이디어는 매우 간단합니다. "변동성이 큰 시장의 단기 추세는 거의 무작위에 가깝습니다." 이것은 어떤 상황에서 여러 Expert에 의해 관찰되었습니다.

마치 살아있는 생물처럼 현실 세계에서 EA를 생각한 직후입니다. 이 비전 덕분에 우리는 Forex 기계가 뇌, 진화라고 부르는 것, 차트의 세 가지 주요 부분으로 구성될 수 있다는 것을 알았습니다.

그리고 마지막으로 백테스트를 실행하는 데 필요한 논리를 통합하는 시스템의 Expert 조언자를 프로그래밍했으며 2012년 1월에 로봇을 여러 번 실행했으며 대부분의 경우 시스템이 이기는 것으로 나타났습니다. 이 시스템의 이면에 있는 아이디어는 사실로 입증되었지만 단순성으로 인해 효율성이 그리 높지 않습니다.


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

파일 첨부됨 |
cbrain.mqh (5.64 KB)
cevolution.mqh (2.97 KB)
cgraphic.mqh (3.55 KB)
enums.mqh (0.92 KB)
csimplerandom.mqh (12.79 KB)
MQL5 마법사 및 Hlaiman EA 생성기를 사용하여 신경망 EA 생성 MQL5 마법사 및 Hlaiman EA 생성기를 사용하여 신경망 EA 생성
이 글에서는 MQL5 Wizard 및 Hlaiman EA Generator를 사용하여 신경망 EA를 자동으로 생성하는 방법을 설명합니다. 이론적인 정보 전체를 배우고 코드를 작성하지 않고도 신경망 작업을 쉽게 시작할 수 있는 방법을 보여줍니다.
계산을 위해 OpenCL을 설치하고 사용하는 방법 계산을 위해 OpenCL을 설치하고 사용하는 방법
MQL5가 OpenCL에 대한 기본 지원을 제공하기 시작한 지 1년이 넘었습니다. 그러나 Expert Advisors, 지표 또는 스크립트에서 병렬 컴퓨팅 사용의 진정한 가치를 본 사용자는 많지 않습니다. 이 문서는 MetaTrader 5 거래 터미널에서 이 기술을 사용할 수 있도록 컴퓨터에 OpenCL을 설치하고 설정하는 데 도움이 됩니다.
자동 뉴스 거래자 구축 자동 뉴스 거래자 구축
이것은 처음부터 간단한 OO EA를 빌드하는 방법을 보여주고 객체 지향 프로그래밍에 대한 몇 가지 팁을 제공한 또 다른 MQL5 OOP 클래스 글의 연속입니다. 오늘은 뉴스를 거래할 수 있는 EA를 개발하는 데 필요한 기술적인 기본 사항을 보여 드리겠습니다. 제 목표는 계속해서 OOP에 대한 아이디어를 제공하고 파일 시스템으로 작업하는 이 일련의 글에서 새로운 주제를 다루는 것입니다.
MQL5 Coobook: 일반적인 차트 이벤트 처리 MQL5 Coobook: 일반적인 차트 이벤트 처리
이 문서에서는 일반적인 차트 이벤트를 고려하고 처리 예를 포함합니다. 우리는 차트 수정 이벤트에 대해서 뿐 아니라 마우스 이벤트, 키 입력, 그래픽 개체 생성/수정/제거, 차트 및 그래픽 개체에 대한 마우스 클릭, 마우스로 그래픽 개체 이동, 텍스트 필드의 텍스트 편집 완료에 중점을 둘 것입니다. 고려되는 각 이벤트 유형에 대해 MQL5 프로그램 샘플이 제공됩니다.