English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
MQL5 프로그래밍 기초: 터미널 글로벌 변수

MQL5 프로그래밍 기초: 터미널 글로벌 변수

MetaTrader 5 | 12 10월 2021, 16:23
170 0
Denis Kirichenko
Denis Kirichenko

들어가며

MQL4/5 환경에는 클라이언트 터미널의 글로벌 변수라는 흥미로는 요소가 있습니다. 이를 통해서 터미널 내의 모든 프로그램들이 공유할 수 있는 데이터 저장공간을 만들 수 있습니다. 또한 이 영역의 데이터는 터미널이 청산된다고해서 사라지지 않습니다. 이 문서에서는 객체 지향 프로그래밍(Object Oriented Programming) 도구를 사용하여 터미널의 글로벌 변수란 무엇인지에 대해 알아볼 것입니다.

또한 이 문서에서 클라이언트의 글로벌 변수를 따로 언급하지않는 한 "글로벌 변수"라고 지칭합니다.


1. 글로벌 변수, 함수들

프로그래머의 관점에서 설명하자면, 글로벌 변수는 매매 터미널의 모든 작업 프로그램에서 사용할 수 있는 명명된 메모리 영역입니다. 초보 프로그래머는 동시에 작동하는 여러 터미널이 있는 경우 각 터미널에 전역 변수에 대한 자체 독립 메모리 공간이 있다는 점에 유의해야 합니다. 겹치는 일이 없기 때문입니다.

개발자용 설명서에 의하면 글로벌 변수를 다루는 함수는 총 11개 있음을 알 수 있습니다.

이론적인 부분은 MQL4 책의 "글로벌 변수(GlobalVariables)" 섹션에서 찾아볼 수 있습니다.

이후 섹션에서는 셋 태스크 구현을 위해 객체 지향 프로그래밍(Object-oriented programming)을 사용할 것입니다.


2. CGlobalVar 클래스

객체 지향 프로그래밍의 근간 아이디어들을 빌려서 글로벌 변수 객체가 될 CGlobalVar 클래스를 만들어봅시다.

//+------------------------------------------------------------------+
//| Class CGlobalVar                                                 |
//+------------------------------------------------------------------+
class CGlobalVar : public CObject
  {
   //--- === Data members === --- 
private:
   string            m_name;
   double            m_value;
   //---
   datetime          m_create_time;
   datetime          m_last_time;
   //--- flag for temporary var
   bool              m_is_temp;

   //--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CGlobalVar(void);
   void              CGlobalVar(const string _var_name,const double _var_val,
                                const datetime _create_time);
   void             ~CGlobalVar(void){};
   //--- create/delete
   bool              Create(const string _var_name,const double _var_val=0.0,
                            const bool _is_temp=false);
   bool              Delete(void);
   //--- exist
   bool              IsGlobalVar(const string _var_name,bool _to_print=false);

   //--- set methods
   bool              Value(const double _var_val);
   bool              ValueOnCondition(const double _var_new_val,const double _var_check_val);

   //--- get methods
   string            Name(void) const;
   datetime          CreateTime(void) const;
   datetime          LastTime(void);
   template<typename T>
   T                 GetValue(T _type) const;
   bool              IsTemporary(void) const;
   //---
private:
   string            FormName(const string _base_name,const bool _is_temp=false);
  };

-->

클래스에는 무얼 인클루드 해야할까요? 최소 속성 목록의 경우 다음 속성을 선택합니다:

  • 변수의 이름;
  • 변수의 값;
  • 생성 시점;
  • 최종 호출 시점;
  • 임시 변수의 기능.

메소드는 다음과 같습니다:

  • 생성;
  • 삭제;
  • 기존 존재 확인;
  • 신규 값 설정;
  • 조건부로 새 값 설정하기;
  • 이름 받기;
  • 값 받기;
  • 임시 변수 플래그 받기.

CGlobalVar::GetValue 메소드는 따로 언급되어야합니다. 이는 템플릿 메소드입니다. 이 메소드는 유저가 매개변수로 설정한 변수 값의 데이터 타입을 반환합니다.

문제는 MQL에서의 함수는 패러미터를 통해 작성할 수 밖에 없다는 것입니다. 따라서 가짜 패러미터를 추가할 필요가 있습니다.

CGlobalVar 타입 객체들을 다룰 테스트 스크립트 Globals_test1.mq5를 작성해봅시다.

#include "CGlobalVar.mqh"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   CGlobalVar gVar1;
//--- create a temporary global var
   if(gVar1.Create("Gvar1",3.123456789101235,true))
     {
      Print("\n---=== A new global var ===---");
      PrintFormat("Name: \"%s\"",gVar1.Name());
      PrintFormat("Is temporary: %d",gVar1.IsTemporary());

      //--- Get the value 
      //--- double type
      double d=0.0;
      double dRes=gVar1.GetValue(d);
      PrintFormat("Double value: %0.15f",dRes);
      //--- float type
      float f=0.0;
      float fRes=gVar1.GetValue(f);
      PrintFormat("Float value: %0.7f",fRes);
      //--- string type
      string s=NULL;
      string sRes=gVar1.GetValue(s);
      PrintFormat("String value: %s",sRes);

      //--- Set a new value 
      double new_val=3.191;
      if(gVar1.Value(new_val))
         PrintFormat("New value is set: %f",new_val);

      //--- Set a new value on condition
      new_val=3.18;
      if(gVar1.ValueOnCondition(3.18,3.191))
         PrintFormat("New value on conditionis set: %f",new_val);
     }
  }

-->

글로벌 변수는 다음과 같이 만들어집니다:

gVar1.Create("Gvar1",3.123456789101235,true)
-->

첫 매개 변수는 미래에 만들 변수명 ("Gvar1")의 기본 구성요소이며, 두번째 매개 변수는 값 (3.123456789101235) 그리고 세번째 매개 변수는 이 변수가 임시 변수일 것을 보여주는 값 (true)입니다.

변수명은 기본 구성 요소에 이름과 프로그램 타입을 추가하는 것으로 생성됩니다.

제 경우엔:

  1. Gvar1 - 기본 구성 요소;
  2. prog_Globals_test1 - 변수가 생성된 프로그램 (이 이름은 Globals_test1);
  3. 프로그램 타입은 - scr (스크립트).

F3을 누르면 MetaTrader5 창의 글로벌 변수 목록이 표시됩니다.

1번 그림. Test_temp_var1_prog_Globals_test1_scr 변수의 값은 3.18

1번 그림. Test_temp_var1_prog_Globals_test1_scr 변수의 값은 3.18

성공적으로 구동시키고 구현했다면 이 내용이 "Experts" 저널 안에 기록됩니다:

KP      0       10:20:20.736    Globals_test1 (AUDUSD.e,H1)     ---=== A new global var ===---
EH      0       10:20:21.095    Globals_test1 (AUDUSD.e,H1)     Name: "Gvar1_temp_prog_Globals_test1_scr"
LF      0       10:20:21.876    Globals_test1 (AUDUSD.e,H1)     Is temporary: 1
MO      0       10:20:31.470    Globals_test1 (AUDUSD.e,H1)     Double value: 3.123456789101235
KG      0       10:20:31.470    Globals_test1 (AUDUSD.e,H1)     Float value: 3.1234567
OP      0       10:20:31.470    Globals_test1 (AUDUSD.e,H1)     String value: 3.123456789101235
RH      0       10:20:31.470    Globals_test1 (AUDUSD.e,H1)     New value is set: 3.191000
DJ      0       10:20:31.470    Globals_test1 (AUDUSD.e,H1)     New value on conditionis set: 3.180000
-->

각 변수 값의 데이터 타입이 저널에 기록됩니다.

만약 MetaTrader 5 터미널이 재기동된다면 Gvar1_temp_prog_Globals_test1_scr 변수는 글로벌 변수 목록에서 사라집니다. 이는 변수가 임시값으로 설정되어있었기때문이고, 터미널이 켜져있을 때에만 유지되었기 때문입니다.

MQL4/5에서는 글로벌 변수를 받아올 때 해당 글로벌 변수가 임시값인지 아닌지를 확인할 수 있는 방법이 없습니다. 어쩌면 임시 변수를 확인하는 가장 쉬운 방법은 변수명에 키를 집어넣는 것일지도 모릅니다. 예를 들어 변수명에 접미어 "temp"를 넣는 방법이 있습니다. 하지만 글로벌 변수 이름에 집어넣는 방법은 CGlobalVar 클래스를 사용하지않는 프로그램들에 의해 생성된 변수 등 일률적으로 적용하기 어렵다는 문제가 있습니다.

얼마나 많은 글로벌 변수가 생성될 수 있으며, 얼마나 빠르게 생성될 수 있는지 알아보고 싶었습니다.

따라서 기존 스크립트를 약간 변경시켜 Globals_test2.mq5라고 명명했습니다. 매번 다른 횟수에 맞춰 실행되었습니다. 변수를 삭제하기 위해 매번 실행 후 터미널을 재기동시켰습니다.

#property script_show_inputs
//---
#include "CGlobalVar.mqh"

input uint InpCnt=10000; // Number of variables
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- start value
   uint start=GetTickCount();
//---
   for(uint idx=0;idx<InpCnt;idx++)
     {
      CGlobalVar gVar;
      //--- Create a temporary global var
      if(!gVar.Create("Test_var"+IntegerToString(idx+1),idx+0.15,true))
         Alert("Error creating a global variable!");
     }
//--- finish value
   uint time=GetTickCount()-start;
//--- to print
   PrintFormat("Creation of %d global variables took %d ms",InpCnt,time);
  }
-->

이게 바로 결과입니다 (2번 그림).

2번 그림. 임시 글로벌 변수를 생성하는데에 소요된 시간

2번 그림. 임시 글로벌 변수를 생성하는데에 소요된 시간

전체 글로벌 변수 용으로 수행된 비슷한 테스트의 결과를 3번 그림에서 확인할 수 있습니다. 딱히 더 오래걸리진 않습니다.

그 이유는 이 변수들은 디스크 내 Profiles 폴더에 위치한 gvariables.dat 파일에 저장되기 때문입니다.

3번 그림. 전체 글로벌 변수를 생성하는데에 소요된 시간

3번 그림. 전체 글로벌 변수를 생성하는데에 소요된 시간

글로벌 변수를 딱히 그렇게 많이 생성할 필요는 없을 것 같습니다. 이 테스트를 해본 것은 그냥 궁금해서입니다.

다음 문단에서 글로벌 변수 세트를 다뤄보겠습니다.


3. CGlobalVarList 클래스

글로벌 변수 작업을 관리하기 위해선 CGlobalVarList 타입의 글로벌 변수들로 구성된 리스트 클래스를 생성해야합니다. 이 타입의 리스트는 표준 리스트 클래스 CList에서 파생되었습니다.

클래스 선언은 다음과 같이 나타납니다:

//+------------------------------------------------------------------+
//| Class CGlobalVarList                                             |
//+------------------------------------------------------------------+
class CGlobalVarList : public CList
  {
   //--- === Data members === --- 
private:
   ENUM_GVARS_TYPE   m_gvars_type;

   //--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CGlobalVarList(void);
   void             ~CGlobalVarList(void){};
   //--- load/unload
   bool              LoadCurrentGlobals(void);
   bool              KillCurrentGlobals(void);
   //--- working with files
   virtual bool      Save(const int _file_ha);
   virtual bool      Load(const int _file_ha);
   //--- service
   void              Print(const int _digs);
   void              SetGvarType(const ENUM_GVARS_TYPE _gvar_type);
   //---
private:
   bool              CheckGlobalVar(const string _var_name);
  };
-->

만약 현재 글로벌 변수들에 연결된 객체들이 CGlobalVarList 타입 리스트에 포함될 예정이라면 CGlobalVarList::LoadCurrentGlobals 메소드가 사용됩니다.

//+------------------------------------------------------------------+
//| Load current global vars                                         |
//+------------------------------------------------------------------+
bool CGlobalVarList::LoadCurrentGlobals(void)
  {
   ENUM_GVARS_TYPE curr_gvar_type=this.m_gvars_type;
   int gvars_cnt=GlobalVariablesTotal();
//---
   for(int idx=0;idx<gvars_cnt;idx++)
     {
      string gvar_name=GlobalVariableName(idx);
      if(this.CheckGlobalVar(gvar_name))
         continue;

      //--- gvar properties
      double gvar_val=GlobalVariableGet(gvar_name);
      datetime gvar_time=GlobalVariableTime(gvar_name);
      CGlobalVar *ptr_gvar=new CGlobalVar(gvar_name,gvar_val,gvar_time);
      //--- control gvar type 
      if(CheckPointer(ptr_gvar)==POINTER_DYNAMIC)
        {
         if(curr_gvar_type>GVARS_TYPE_ALL)
           {
            bool is_temp=ptr_gvar.IsTemporary();
            //--- only full-fledged
            if(curr_gvar_type==GVARS_TYPE_FULL)
              {if(is_temp)continue;}
            //--- only temporary
            else if(curr_gvar_type==GVARS_TYPE_TEMP)
              {if(!is_temp)continue;}
           }
         //--- try to add
         if(this.Add(ptr_gvar)>-1)
            continue;
        }
      //---
      return false;
     }
//---
   return true;
  }

-->

이 메소드는 현재 존재하는 모든 글로벌 변수를 읽어들여서 리스트에 추가합니다.

m_gvars_type 요소를 통해 포함된 글로벌 변수의 타입을 관리합니다. 혹시 ENUM_GVARS_TYPE 타입의 열거일까요:

//+------------------------------------------------------------------+
//| Enumeration for gvars type                                       |
//+------------------------------------------------------------------+
enum ENUM_GVARS_TYPE
  {
   GVARS_TYPE_ALL=-1,  // all global
   GVARS_TYPE_FULL=0,  // only full
   GVARS_TYPE_TEMP=1,  // only temporary
  };

-->

CGlobalVarList 리스트를 초기화하기 전에 먼저 그렇다고 가정해봅시다. 4번 그림에 나타난 것 처럼 글로벌 변수 세트가 있습니다.

4번 그림. 개략적인 글로벌 변수 세트

4번 그림. 개략적인 글로벌 변수 세트

이 세트가 리스트에 의해 올바르게 처리되는지 확인해볼 것입니다. 체크를 수행하기 위하여 Globals_test3.mq5 테스트 스크립트가 생성될 것입니다.

#include "CGlobalVarList.mqh"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   CGlobalVarList gvarList;
   gvarList.LoadCurrentGlobals();   
   PrintFormat("Number of variables in the set: %d",gvarList.Total());
  }

-->

원래는 생길 일이 없었을 새로운 글로벌 변수 (노란색으로 강조됨) 들이 스크립트 실행 이후에 나타납니다.

5번 그림. 새로운 글로벌 변수 세트

5번 그림. 새로운 글로벌 변수 세트

스트링은 다음과 같이 출력되었습니다.

2014.10.21 11:35:00.839       Globals_test3 (AUDUSD.e,H1)              Number of variables in the list: 10

-->

이는 CGlobalVarList::LoadCurrentGlobals 메소드의 선언에 CGlobalVar::Create 메소드의 레퍼런스가 있기 때문입니다.

다시 말해 스트링 안에 새로운 글로벌 변수가 생성되었다는 말입니다:

if(ptr_gvar.Create(gvar_name,gvar_val))
-->

추가적으로 그 글로벌 변수들의 인덱스가 새 변수들이 등장함에 따라 변경됩니다. 이로 인해 혼란이 초래되죠.

CGlobalVar::Create 메소드를 상대적으로 덜 활성화된 메소드로 교체하는 것을 추천드립니다. CGlobalVar 클래스에 패러미터를 수반한 생성자가 덧붙여져야 변수를 리스트 내에 제대로 반영할 수 있습니다.

수정 후 CGlobalVarList::LoadCurrentGlobals 메소드는 다음과같이 보일 것입니다.

//+------------------------------------------------------------------+
//| Load current global vars                                         |
//+------------------------------------------------------------------+
bool CGlobalVarList::LoadCurrentGlobals(void)
  {
   int gvars_cnt=GlobalVariablesTotal();
//---
   for(int idx=0;idx<gvars_cnt;idx++)
     {
      string gvar_name=GlobalVariableName(idx);
      double gvar_val=GlobalVariableGet(gvar_name);
      datetime gvar_time=GlobalVariableTime(gvar_name);
      CGlobalVar *ptr_gvar=new CGlobalVar(gvar_name,gvar_val,gvar_time);
      if(CheckPointer(ptr_gvar)==POINTER_DYNAMIC)
         if(this.Add(ptr_gvar)>-1)
            continue;
      //---
      return false;
     }
//---
   return true;
  }
-->

메소드가 수정된 후 스크립트는 정상적으로 작동됩니다. 이하의 기록이 출력됩니다.

2014.10.21 11:38:04.424      Globals_test3 (AUDUSD.e,H1)              Number of variables in the list: 6
-->

이후에 리스트 삭제와 프린팅을 가능하게 해주는 기능을 추가합니다.

그 후 Globals_test3.mq5는 다음과 같이 보입니다.

//---
#include "CGlobalVarList.mqh"
//---
input ENUM_GVARS_TYPE InpGvarType=GVARS_TYPE_FULL; // Set gvar type
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   CGlobalVarList gvarList;
//--- delete gvars
   gvarList.SetGvarType(InpGvarType);
//--- load current gvars  
   gvarList.LoadCurrentGlobals();
   Print("Print the list before deletion.");
   gvarList.Print(10);
//--- delete gvars
   if(gvarList.KillCurrentGlobals())
     {
      Print("Print the screen after deletion.");
      gvarList.Print(10);
     }
  }

-->

10개의 다양한 글로벌 변수를 생성하여 좀 더 복잡하게해보겠습니다 (6번 그림).

6번 그림. 다양한 글로벌 변수

6번 그림. 다양한 글로벌 변수

우리의 리스트 gvarList 에는 완전 변수만이 추가됩니다. 그 후 삭제되죠.

"Expert" 저널엔 다음의 내용이 담기게 됩니다.

MG      0       11:05:01.113    Globals_test3 (AUDUSD.e,H1)     Print the list before deletion.
KL      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     
OI      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     ---===Local list===---
QS      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Global variable type: GVARS_TYPE_FULL
RI      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Total number of global variables: 10
EG      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Number of global variables in current list: 5
RN      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Gvar #1, name - gVar10_prog_test1_scr, value - 16.6400000000
KP      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Gvar #2, name - gVar2_prog_test1_scr, value - 4.6400000000
GR      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Gvar #3, name - gVar4_prog_test1_scr, value - 7.6400000000
RD      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Gvar #4, name - gVar6_prog_test1_scr, value - 10.6400000000
LJ      0       11:05:01.613    Globals_test3 (AUDUSD.e,H1)     Gvar #5, name - gVar8_prog_test1_scr, value - 13.6400000000
EH      0       11:06:18.675    Globals_test3 (AUDUSD.e,H1)     Print the list after deletion.
FS      0       11:06:19.003    Globals_test3 (AUDUSD.e,H1)     
JJ      0       11:06:19.003    Globals_test3 (AUDUSD.e,H1)     ---===Local list===---
HN      0       11:06:19.003    Globals_test3 (AUDUSD.e,H1)     Global variable type: GVARS_TYPE_FULL
KH      0       11:06:19.003    Globals_test3 (AUDUSD.e,H1)     Total number of global variables: 5
QP      0       11:06:19.003    Globals_test3 (AUDUSD.e,H1)     Number of global variables in the current list: 0
-->

리스트엔 제대로 생성된 완전 글로벌 변수만이 기록됩니다.

그 후에 삭제되어 터미널에는 딱 5개의 임시 변수만이 남습니다 (7번 그림).

7번 그림. 임시 글로벌 변수

7번 그림. 임시 글로벌 변수

이렇게 목표가 달성됩니다.

CGlobalVarList 클래스 내에 데이터를 파일에 저장하는 메소드와 파일에서 데이터를 다운받는 메소드가 구현되었습니다.


4. 실용적인 어플리케이션

아시겠다시피 MQL4/5는 특화된 프로그래밍 언어입니다. 이 언어들은 매매 전략을 프로그래밍하기 위하여 만들어졌습니다. 그렇기 때문에 이 언어에선 어떤 도구를 활용하건간에 특정 매매 전략을 공식화하는 수단으로 사용하게됩니다.

MQL5 플랫폼의 글로벌 변수와 Expert Advisor들을 연결하는 예시는 흔하게 찾아볼 수 있습니다.. 일단은 프로그램 구현에 대한 제어가 필요한 상황을 자세히 살펴보실 것을 추천드리겠습니다.

모듈적 접근에 기반을 둔 매매 봇 "Globals_test_EA" 의 코드가 있다고 가정해봅시다.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   return INIT_SUCCEEDED;
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   Comment("");
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   Main();
  }
-->

메인 모듈은 이런 느낌일 것입니다.

//+------------------------------------------------------------------+
//| Main module                                                      |
//+------------------------------------------------------------------+
void Main(void)
  {
//--- set flags for all modules
   for(int idx=0;idx<GVARS_LIST_SIZE;idx++)
      SetFlag(idx,false);

//--- Check the trade possibility and connectivity
//--- permission to trade
   if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
      //--- connection to the trading server
      if(TerminalInfoInteger(TERMINAL_CONNECTED))
         //--- permission to trade for the launched EA
         if(MQLInfoInteger(MQL_TRADE_ALLOWED))
           {
            //--- 1) opening module
            Open();
            //--- 2) closing module
            Close();
            //--- 3) Trailing Stop module
            Trail();
           }
  }

-->

이 메인 모듈은 세개의 구성요소를 내포하고 있습니다.

  1. 여는 모듈.
  2. 닫는 모듈.
  3. 추적 손절매 모듈

이제 프로그램 실행 단계를 제어하는 글로벌 변수를 만들어야 합니다.

모듈 형태로 된 3개의 스테이지가 있습니다. 각 스테이지에는 두개의 컨트롤 포인트가 있습니다. 첫 번째 제어점은 모듈 작업의 시작을 제어하고 두 번째 제어점은 모듈 작업의 끝을 제어합니다.

컨트롤 포인트는 글로벌 변수의 형태로 구현되어있습니다.

따라서 총 6개의 글로벌 변수가 필요합니다.

//--- global variables: names
string gVar_names[6]=
  {
   "gvarOpen_start","gvarOpen_finish",
   "gvarClose_start","gvarClose_finish",
   "gvarTrail_start","gvarTrail_finish"
  };

-->

모든 모듈 용 플래그는 Main() 함수 도입부에서 설정되어 각 모듈에서 제거됩니다. "자기" 플래그만 처리하게됩니다. 예를들어 Open() 모듈을 봅시다.

//+------------------------------------------------------------------+
//| Open module                                                      |
//+------------------------------------------------------------------+
void Open(void)
  {
   Comment(curr_module+__FUNCTION__);
//---
   if(!IsStopped())
     {
      //--- clear the module start flag
      SetFlag(0,true);

      //--- assume that the module operates for approximately 1.25 s
        {
         Sleep(1250);
        }
      //--- clear the module finish flag
      SetFlag(1,true);
     }
  }

-->

모듈 실행 중에, 프로그램이 현재 Open() 블록을 처리중이라는 코멘트가 차트 창에 나타나게 됩니다.

그 후 만약 프로그램이 강제 종료되지않는다면 컨트롤이 해당하는 플래그를 설정하고/치우는 함수로 전달됩니다. 만약 그런 컨트롤 포인트를 처리하지 못한 경우엔 해당 모듈은 작업을 완수하지 못한것으로 간주됩니다.

글로벌 변수를 이용하여 모듈 스테이지를 추적하는 패턴을 8번 그림에서 볼 수 있습니다.

8번 그림. 플래그 시퀀스 처리 패턴

8번 그림. 플래그 시퀀스 처리 패턴

예를 들어 "Globals_test_EA" Expert Advisor가 차트에 부착되어 정상적으로 작동중이라고해봅시다.

제가 만약 차트에서 그 Expert Advisor를 제고하게되는 경우 저널엔 다음 엔트리가 나타납니다.

2014.10.22 20:14:29.575 Globals_test_EA (EURUSD.e,H1)   Program forced to terminate before execution: <<Open_finish>>

-->

그렇게 Open().모듈의 Expert Advisor가 종료됩니다.

F3을 눌러 글로벌 변수 목록을 여십시오 (9번 그림).

9번 그림. "Globals_test_EA" Expert Advisor의 글로벌 변수

9번 그림. "Globals_test_EA" Expert Advisor의 글로벌 변수

리스트를 대충 보건데 Open() 모듈 시작을 담당하는 플래그만이 0으로 바뀌었습니다.

개방 포지션, 청산 및 유지보수와 관련된 명령 실행 실패 시 결함을 잠재적으로 감지할 수 있는 것으로 보입니다.

동일한 차트에서 봇을 다시 실행하면 저널에 다음 정보가 표시됩니다.

RQ      0       20:28:25.135    Globals_test_EA (EURUSD.e,H1)   Non-zero value for: <<Open_finish>>
CL      0       20:28:25.135    Globals_test_EA (EURUSD.e,H1)   Non-zero value for: <<Close_start>>
DH      0       20:28:25.135    Globals_test_EA (EURUSD.e,H1)   Non-zero value for: <<Close_finish>>
ES      0       20:28:25.135    Globals_test_EA (EURUSD.e,H1)   Non-zero value for: <<Trail_start>>
RS      0       20:28:25.135    Globals_test_EA (EURUSD.e,H1)   Non-zero value for: <<Trail_finish>>
-->

이런 식으로 우리는 프로그램 단계의 실패에 대한 경고를 받습니다. 이를 통해 다른 의문을 가질 수 있게 됩니다. 만약 이 단계들이 실패한다면 어떻게 해야할까요? 그건 나중에 기회가 되면 또 다뤄보겠습니다.


마치며

지금까지 이 문서에서 MQL5 언어에서 객체 지향 기능을 활용하여 터미널 내의 글로벌 변수를 다루어 객체를 생성하는 가능성들에 대해 알아보았습니다.

프로그램 단계의 구현을 위한 제어점으로 글로벌 변수를 사용한 경우를 예로 들 수 있습니다.

언제나처럼 댓글, 제안, 그리고 건전한 비판을 부탁드립니다.


MetaQuotes 소프트웨어 사를 통해 러시아어가 번역됨.
원본 기고글: https://www.mql5.com/ru/articles/1210

파일 첨부됨 |
globals_test1.mq5 (3.67 KB)
globals_test2.mq5 (2.92 KB)
globals_test3.mq5 (2.59 KB)
cglobalvar.mqh (20.52 KB)
cglobalvarlist.mqh (18.74 KB)
globals_test_ea.mq5 (13.01 KB)
트레이더의 통계 도우미: 가설들 트레이더의 통계 도우미: 가설들
이 문서에서는 수리통계학의 기초 중 하나인 가설에 대해 다뤄보겠습니다. 다양한 가설들은 실제 예시에 수리통계적 관점으로 접근해서 검토, 검증됩니다. 실제 데이터는 비모수적 방법을 사용하여 일반화됩니다. 데이터 처리에는 Statistica 패키지와 포팅된 ALGLIB MQL5 수리분석 라이브러리가 사용됩니다.
리퀴드 차트 리퀴드 차트
매 시간별 2분과 5분을 기준으로 열리는 바가 있는 시간당 차트를 보고 싶진 않으신가요? 1분마다 바가 열리는 시간이 바뀌는 차트는 어떤 모양으로 나타날까요? 이런 차트를 이용하면 거래에 도움이 될까요? 아래에서 그 답을 알아보겠습니다.
객체지향적 접근을 이용하여 EA 모드 프로그래밍하기 객체지향적 접근을 이용하여 EA 모드 프로그래밍하기
이 문서에서는 MQL5에서 멀티모드용 봇 프로그램을 짜는 아이디어에 대해 논해볼 것입니다. 모드들은 객체지향적 접근으로 구현되었습니다. 모드 클래스 계층 구조와 테스트용 클래스의 인스턴스가 모두 제공됩니다. 트레이딩 봇의 멀티 모드 프로그래밍은 MQL5로 작성된 EA의 모든 작동 모드의 모든 특성을 고려해야 합니다. 해당 모드를 식별하기 위해 함수나 열거가 생성됩니다.
MQL4, MQL5로 프랙탈을 이용한 추세선 그리기 MQL4, MQL5로 프랙탈을 이용한 추세선 그리기
이번 글에서는 MQL4와 MQL5로 프랙탈 인디케이터를 기반으로 하는 자동 추세선 플로팅에 관한 내용을 다룹니다. 두 언어의 솔루션을 서로 비교할 수 있도록 작성되었습니다. 추세선은 가장 마지막으로 생성된 두 개의 프랙탈을 기반으로 플로팅됩니다.