
MQL5 Cookbook: 사용자 지정 정보 패널의 포지션 속성
소개
이번에는 현재 기호에 대한 포지션 속성을 가져와 수동 거래 중에 사용자 지정 정보 패널에 표시하는 간단한 Expert Advisor를 만들 것입니다. 정보 패널은 그래픽 개체를 사용하여 생성되며 표시된 정보는 틱마다 새로 고쳐집니다. 이것은 "MQL5 Cookbook: Get Position Properties" 시리즈의 이전 글에서 설명한 스크립트를 수동으로 실행해야 하는 모든 시간보다 훨씬 편리할 것입니다.
Expert Advisor 개발
그래픽 개체부터 시작하겠습니다. 정보 패널을 만들려면 배경, 헤더, 이름 및 포지션 속성 값에 대한 개체가 필요합니다. 배경과 헤더에는 가격과 함께 움직이지 않는 직사각형이 필요합니다. 직사각형은 사각형 레이블 또는 편집과 같은 그래픽 개체를 사용하여 만들 수 있으며 개체 속성의 이름과 값은 텍스트 레이블을 사용하여 만듭니다.
코드를 진행하기 전에 먼저 정보 패널의 레이아웃을 준비합니다. 그 편의성은 설정 창에서 속성을 빠르게 변경하고 정보 패널의 모양을 사용자 지정할 수 있다는 사실에 있습니다.
모든 개체에는 선택한 개체의 상황에 맞는 메뉴에서 열 수 있는 설정 창이 있습니다. 설정 창은 필요한 개체를 선택하고 속성을 클릭하여 개체 목록(Ctrl+B)에서 열 수도 있습니다. 정보 패널 레이아웃은 아래와 같습니다. 코드를 작성할 때 크기와 좌표를 추정하는 데에도 사용할 수 있습니다. 정보 패널의 코드가 준비되면 Expert Advisor가 레이아웃 개체를 '볼' 수 없으므로 차트에서 제거하지 않으므로 수동으로 레이아웃 개체를 삭제해야 합니다.
그림 1. 정보 패널의 레이아웃을 준비합니다.
이제 Expert Advisor용 템플릿을 만들어야 합니다. 이것은 스크립트만큼 빠르게 수행할 수 있습니다. MQL5 마법사에서는 기본적으로 Expert Advisor(템플릿) 옵션이 선택됩니다. 이번에는 필요하지 않으므로 옵션을 변경하지 않고 다음 단계를 진행합니다. 그런 다음 마침을 클릭하면 아래와 같은 템플릿이 표시됩니다.
//+------------------------------------------------------------------+ //| PositionPropertiesPanel.mq5 | //| Copyright 2012, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2012, MetaQuotes Software Corp." #property link "http://www.mql5.com" #property version "1.00" //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(0); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+
Expert Advisor 템플릿이 스크립트 템플릿과 다르다는 것을 바로 알 수 있습니다. 프로그램 속성(#property) 외에도 OnInit(), OnDeinit() 및 OnTick()의 세 가지 주요 기능이 있습니다.
OnInit() 함수는 프로그램을 로드할 때, 외부 매개변수를 변경할 때, 프로그램을 컴파일할 때 호출됩니다. 단, 기호 또는 기간을 변경할 때 프로그램은 바로 그 때 차트에 추가됩니다. 필요한 경우 나중에 사용할 수 있도록 이 함수의 특정 변수 또는 배열을 초기화할 수 있습니다.
OnDeinit() 함수는 차트에서 프로그램을 삭제하거나 계정, 기호 또는 기간을 변경할 때 호출됩니다. 가능한 모든 초기화 해제 이유는 MQL5 참조에 나와 있습니다. 이 Expert Advisor는 초기화 해제 이유 식별자(OnDeinit() 함수 매개변수)를 텍스트로 변환하는 사용자 정의 함수 GetDeinitReasonText()를 사용합니다.
마지막으로 OnTick() 함수입니다. Expert Advisor가 현재 작동 중인 차트의 기호에 새 틱이 있을 때마다 호출됩니다.
이제 Expert Advisor에서 사용할 모든 상수, 변수 및 배열을 준비하겠습니다. 우리는 그것들을 프로그램의 맨 처음에 배치할 것입니다. 먼저 프로그램 전체에서 값이 변경되지 않은 상태로 유지되는 변수를 정의합니다.
//--- #define INFOPANEL_SIZE 14 // Size of the array for info panel objects #define EXPERT_NAME MQL5InfoString(MQL5_PROGRAM_NAME) // Name of the Expert Advisor //---
다음은 포지션 속성에 대한 전역 변수입니다.
//--- GLOBAL VARIABLES bool pos_open=false; // Flag of presence/absence of an open position string pos_symbol=""; // Symbol long pos_magic=0; // Magic number string pos_comment=""; // Comment double pos_swap=0.0; // Swap double pos_commission=0.0; // Commission double pos_price=0.0; // Position price double pos_cprice=0.0; // Current price of the position double pos_profit=0.0; // Profit/Loss of the position double pos_volume=0.0; // Position volume double pos_sl=0.0; // Stop Loss of the position double pos_tp=0.0; // Take Profit of the position datetime pos_time=NULL; // Position opening time long pos_id=0; // Position identifier ENUM_POSITION_TYPE pos_type=WRONG_VALUE; // Position type
변수 다음에 그래픽 개체 이름의 배열을 선언합니다. 이러한 개체는 차트에 포지션 속성과 해당 값을 표시합니다. 이를 위해 두 개의 문자열 배열을 만들고 해당 요소를 값으로 즉시 초기화합니다. 대괄호 안에는 프로그램의 맨 처음에 선언된 INFOPANEL_SIZE 상수 값을 사용합니다. 즉, 각 배열에는 14개의 요소가 있습니다.
// Array of names of objects that display names of position properties string positionPropertyNames[INFOPANEL_SIZE]= { "name_pos_symbol", "name_pos_magic", "name_pos_comment", "name_pos_swap", "name_pos_commission", "name_pos_price", "name_pos_cprice", "name_pos_profit", "name_pos_volume", "name_pos_sl", "name_pos_tp", "name_pos_time", "name_pos_id", "name_pos_type" }; //--- // Array of names of objects that display values of position properties string positionPropertyValues[INFOPANEL_SIZE]= { "value_pos_symbol", "value_pos_magic", "value_pos_comment", "value_pos_swap", "value_pos_commission", "value_pos_price", "value_pos_cprice", "value_pos_profit", "value_pos_volume", "value_pos_sl", "value_pos_tp", "value_pos_time", "value_pos_id", "value_pos_type" }; //---
이러한 이름을 사용하여 차트에서 필요한 개체를 프로그래밍 방식으로 찾고 표시된 텍스트, 색상, 크기 등과 같은 속성을 설정하거나 변경할 수 있습니다. 또한 이러한 이름은 차트에서 생성된 후 개체 목록(Ctrl+B) 창에 표시됩니다. 그러나 MQL5 프로그램에 의해 생성된 개체는 기본적으로 숨겨져 있으므로 거기에서 볼 수 없습니다. 표시되도록 하려면 개체 목록 창에서 모두 나열을 클릭해야 합니다. 이 기능은 프로그래밍 방식으로 만든 개체와 수동으로 만든 개체를 구분하는 데 도움이 되며 매우 편리합니다.
또한 Expert Advisor가 그래픽 개체를 생성하는 데 사용할 사용자 정의 기능이 필요합니다. 그래픽 개체 생성을 위해 MQL5에서 제공하는 기능은 ObjectCreate()입니다. 하지만 개체 속성도 설정해야 하기 때문에 개체 자체는 두 번 이상 생성해야 할 수도 있으므로 한 줄의 코드로 구현할 수 있는 보다 편리하고 간결한 방법을 생각하는 것이 좋습니다
정보 패널 배경과 헤더를 생성하기 위해 그래픽 개체 편집을 사용할 것입니다. CreateEdit() 함수를 작성해 보겠습니다.
//+------------------------------------------------------------------+ //| CREATING THE EDIT OBJECT | //+------------------------------------------------------------------+ void CreateEdit(long chart_id, // chart id int sub_window, // (sub)window number string name, // object name string text, // displayed text ENUM_BASE_CORNER corner, // chart corner string font_name, // font int font_size, // font size color font_color, // font color int x_size, // width int y_size, // height int x_distance, // X-coordinate int y_distance, // Y-coordinate long z_order, // Z-order color background_color, // background color bool read_only) // Read Only flag { // If the object has been created successfully,... if(ObjectCreate(chart_id,name,OBJ_EDIT,sub_window,0,0)) { // ...set its properties ObjectSetString(chart_id,name,OBJPROP_TEXT,text); // displayed text ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner); // set the chart corner ObjectSetString(chart_id,name,OBJPROP_FONT,font_name); // set the font ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size); // set the font size ObjectSetInteger(chart_id,name,OBJPROP_COLOR,font_color); // font color ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,background_color); // background color ObjectSetInteger(chart_id,name,OBJPROP_XSIZE,x_size); // width ObjectSetInteger(chart_id,name,OBJPROP_YSIZE,y_size); // height ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x_distance); // set the X coordinate ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y_distance); // set the Y coordinate ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false); // cannot select the object if FALSE ObjectSetInteger(chart_id,name,OBJPROP_ZORDER,z_order); // Z-order of the object ObjectSetInteger(chart_id,name,OBJPROP_READONLY,read_only); // Read Only ObjectSetInteger(chart_id,name,OBJPROP_ALIGN,ALIGN_LEFT); // align left ObjectSetString(chart_id,name,OBJPROP_TOOLTIP,"\n"); // no tooltip if "\n" } }
이제 한 줄의 코드를 사용하여 그래픽 개체 편집(OBJ_EDIT)을 만들 수 있습니다. 차트에 정보 패널을 설정하는 함수를 만들 때 예를 들어 설명하겠습니다.
이제 포지션 속성 및 해당 값 목록을 표시하는 데 사용할 텍스트 레이블 개체를 계속 진행하고 유사한 방식으로 CreateLabel() 함수를 만듭니다.
//+------------------------------------------------------------------+ //| CREATING THE LABEL OBJECT | //+------------------------------------------------------------------+ void CreateLabel(long chart_id, // chart id int sub_window, // (sub)window number string name, // object name string text, // displayed text ENUM_ANCHOR_POINT anchor, // anchor point ENUM_BASE_CORNER corner, // chart corner string font_name, // font int font_size, // font size color font_color, // font color int x_distance, // X-coordinate int y_distance, // Y-coordinate long z_order) // Z-order { // If the object has been created successfully,... if(ObjectCreate(chart_id,name,OBJ_LABEL,sub_window,0,0)) { // ...set its properties ObjectSetString(chart_id,name,OBJPROP_TEXT,text); // displayed text ObjectSetString(chart_id,name,OBJPROP_FONT,font_name); // set the font ObjectSetInteger(chart_id,name,OBJPROP_COLOR,font_color); // set the font color ObjectSetInteger(chart_id,name,OBJPROP_ANCHOR,anchor); // set the anchor point ObjectSetInteger(chart_id,name,OBJPROP_CORNER,corner); // set the chart corner ObjectSetInteger(chart_id,name,OBJPROP_FONTSIZE,font_size); // set the font size ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x_distance); // set the X-coordinate ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y_distance); // set the Y-coordinate ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false); // cannot select the object if FALSE ObjectSetInteger(chart_id,name,OBJPROP_ZORDER,z_order); // Z-order of the object ObjectSetString(chart_id,name,OBJPROP_TOOLTIP,"\n"); // no tooltip if "\n" } }
또한 MQL5 참조에서 기능 설명을 살펴보는 것이 좋습니다.
차트에서 삭제되면 Expert Advisor는 이전에 차트에 추가한 모든 개체를 차례로 삭제해야 합니다. 이렇게 하려면 개체 이름을 DeleteObjectByName() 함수에 전달하기만 하면 됩니다. 그런 다음 지정된 이름으로 개체를 검색하고 개체를 검색하는 기본 제공 ObjectFind() 함수와 ObjectDelete( ) 개체를 삭제하는 함수입니다.
//+------------------------------------------------------------------+ //| DELETING THE OBJECT BY NAME | //+------------------------------------------------------------------+ void DeleteObjectByname(string name) { int sub_window=0; // Returns the number of the subwindow where the object is located bool res =false; // Result following an attempt to delete the object //--- Find the object by name sub_window=ObjectFind(ChartID(),name); //--- if(sub_window>=0) // If it has been found,.. { res=ObjectDelete(ChartID(),name); // ...delete it //--- // If an error occurred when deleting the object,.. if(!res) // ...print the relevant message { Print("Error deleting the object: ("+IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError())); } } }
또한 DeleteObjectByName() 함수에서 개체를 삭제할 때 오류 검사도 구현합니다. 오류가 발생하면 오류 코드와 설명이 포함된 관련 메시지가 나타납니다. 위의 코드에서 볼 수 있듯이 오류 코드를 텍스트 설명으로 변환하는 추가 사용자 정의 함수인 ErrorDescription() 함수를 사용합니다. 오류 코드가 많기 때문에 이 기능의 일부만 사용하여 위의 예를 보여 드리겠습니다(아래 코드 참조). 코드의 전체 버전은 이 글에 첨부된 소스 코드 파일에서 찾을 수 있습니다.
//+------------------------------------------------------------------+ //| RETURNING THE ERROR DESCRIPTION | //+------------------------------------------------------------------+ string ErrorDescription(int error_code) { string error_string=""; //--- switch(error_code) { //--- Trade server return codes case 10004: error_string="Requote"; break; case 10006: error_string="Request rejected"; break; case 10007: error_string="Request canceled by trader"; break; case 10008: error_string="Order placed"; break; case 10009: error_string="Request executed"; break; case 10010: error_string="Request executed partially"; break; case 10011: error_string="Request processing error"; break; case 10012: error_string="Request timed out"; break; case 10013: error_string="Invalid request"; break; case 10014: error_string="Invalid request volume"; break; case 10015: error_string="Invalid request price"; break; case 10016: error_string="Invalid Stop orders in the request"; break; case 10017: error_string="Trading forbidden"; break; case 10018: error_string="Market is closed"; break; case 10019: error_string="Insufficient funds"; break; case 10020: error_string="Prices changed"; break; case 10021: error_string="No quotes to process the request"; break; case 10022: error_string="Invalid order expiration in the request"; break; case 10023: error_string="Order status changed"; break; case 10024: error_string="Too many requests"; break; case 10025: error_string="No changes in the request"; break; case 10026: error_string="Automated trading is disabled by trader"; break; case 10027: error_string="Automated trading is disabled by the client terminal"; break; case 10028: error_string="Request blocked for processing"; break; case 10029: error_string="Order or position frozen"; break; case 10030: error_string="The specified type of order execution by balance is not supported"; break; case 10031: error_string="No connection with trade server"; break; case 10032: error_string="Transaction is allowed for live accounts only"; break; case 10033: error_string="You have reached the maximum number of pending orders"; break; case 10034: error_string="You have reached the maximum order and position volume for this symbol"; break; ... } //--- return(error_string); }
이전 글에서 포지션 속성을 가져오는 GetPositionProperties() 함수를 다루었습니다. 이번에는 함수 구조가 조금 더 복잡해집니다. 글로벌 변수 pos_open에 저장되어 있는 열린 포지션의 유무 플래그와 함께 현재 열려 있는 포지션을 확인합니다. 이 정보는 매번 PositionSelect() 함수를 호출하지 않고도 다른 함수에서 필요할 수 있습니다.
그런 다음 열린 포지션이 있으면 해당 속성을 가져오고 그렇지 않으면 모든 변수가 0이 됩니다. 이제 간단한 ZeroPositionProperties() 함수를 작성해 보겠습니다.
//+------------------------------------------------------------------+ //| ZEROING OUT VARIABLES FOR POSITION PROPERTIES | //+------------------------------------------------------------------+ void ZeroPositionProperties() { pos_symbol =""; pos_comment =""; pos_magic =0; pos_price =0.0; pos_cprice =0.0; pos_sl =0.0; pos_tp =0.0; pos_type =WRONG_VALUE; pos_volume =0.0; pos_commission =0.0; pos_swap =0.0; pos_profit =0.0; pos_time =NULL; pos_id =0; }
또한 GetPositionProperties() 함수의 끝에서 차트의 정보 패널을 그리거나 업데이트하는 사용자 정의 SetInfoPanel() 함수를 호출합니다.
//+------------------------------------------------------------------+ //| GETTING POSITION PROPERTIES | //+------------------------------------------------------------------+ void GetPositionProperties() { // Check if there is an open position pos_open=PositionSelect(_Symbol); //--- if(pos_open) // If an open position exists, get its properties { pos_symbol =PositionGetString(POSITION_SYMBOL); pos_comment =PositionGetString(POSITION_COMMENT); pos_magic =PositionGetInteger(POSITION_MAGIC); pos_price =PositionGetDouble(POSITION_PRICE_OPEN); pos_cprice =PositionGetDouble(POSITION_PRICE_CURRENT); pos_sl =PositionGetDouble(POSITION_SL); pos_tp =PositionGetDouble(POSITION_TP); pos_type =(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); pos_volume =PositionGetDouble(POSITION_VOLUME); pos_commission =PositionGetDouble(POSITION_COMMISSION); pos_swap =PositionGetDouble(POSITION_SWAP); pos_profit =PositionGetDouble(POSITION_PROFIT); pos_time =(datetime)PositionGetInteger(POSITION_TIME); pos_id =PositionGetInteger(POSITION_IDENTIFIER); } else // If there is no open position, zero out variables for position properties ZeroPositionProperties(); //--- SetInfoPanel(); // Set/update the info panel }
이제 SetInfoPanel() 함수를 작성해 보겠습니다. 아래는 이 코드입니다.
//+------------------------------------------------------------------+ //| SETTING THE INFO PANEL | //|------------------------------------------------------------------+ void SetInfoPanel() { int y_bg=18; // Y-coordinate for the background and header int y_property=32; // Y-coordinate for the list of properties and their values int line_height=12; // Line height //--- int font_size=8; // Font size string font_name="Calibri"; // Font color font_color=clrWhite; // Font color //--- ENUM_ANCHOR_POINT anchor=ANCHOR_RIGHT_UPPER; // Anchor point in the top right corner ENUM_BASE_CORNER corner=CORNER_RIGHT_UPPER; // Origin of coordinates in the top right corner of the chart //--- X-coordinates int x_first_column=120; // First column (names of properties) int x_second_column=10; // Second column (values of properties) //--- Array of Y-coordinates for the names of position properties and their values int y_prop_array[INFOPANEL_SIZE]={0}; //--- Fill the array with coordinates for each line on the info panel y_prop_array[0]=y_property; y_prop_array[1]=y_property+line_height; y_prop_array[2]=y_property+line_height*2; y_prop_array[3]=y_property+line_height*3; y_prop_array[4]=y_property+line_height*4; y_prop_array[5]=y_property+line_height*5; y_prop_array[6]=y_property+line_height*6; y_prop_array[7]=y_property+line_height*7; y_prop_array[8]=y_property+line_height*8; y_prop_array[9]=y_property+line_height*9; y_prop_array[10]=y_property+line_height*10; y_prop_array[11]=y_property+line_height*11; y_prop_array[12]=y_property+line_height*12; y_prop_array[13]=y_property+line_height*13; //--- Background of the info panel CreateEdit(0,0,"InfoPanelBackground","",corner,font_name,8,clrWhite,230,190,231,y_bg,0,C'15,15,15',true); //--- Header of the info panel CreateEdit(0,0,"InfoPanelHeader","POSITION PROPERTIES",corner,font_name,8,clrWhite,230,14,231,y_bg,1,clrFireBrick,true); //--- List of the names of position properties and their values // Property name CreateLabel(0,0,pos_prop_names[0],"Symbol :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[0],2); // Property value CreateLabel(0,0,pos_prop_values[0],GetValInfoPanel(0),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[0],2); //--- CreateLabel(0,0,pos_prop_names[1],"Magic Number :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[1],2); CreateLabel(0,0,pos_prop_values[1],GetValInfoPanel(1),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[1],2); //--- CreateLabel(0,0,pos_prop_names[2],"Comment :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[2],2); CreateLabel(0,0,pos_prop_values[2],GetValInfoPanel(2),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[2],2); //--- CreateLabel(0,0,pos_prop_names[3],"Swap :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[3],2); CreateLabel(0,0,pos_prop_values[3],GetValInfoPanel(3),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[3],2); //--- CreateLabel(0,0,pos_prop_names[4],"Commission :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[4],2); CreateLabel(0,0,pos_prop_values[4],GetValInfoPanel(4),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[4],2); //--- CreateLabel(0,0,pos_prop_names[5],"Open Price :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[5],2); CreateLabel(0,0,pos_prop_values[5],GetValInfoPanel(5),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[5],2); //--- CreateLabel(0,0,pos_prop_names[6],"Current Price :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[6],2); CreateLabel(0,0,pos_prop_values[6],GetValInfoPanel(6),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[6],2); //--- CreateLabel(0,0,pos_prop_names[7],"Profit :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[7],2); CreateLabel(0,0,pos_prop_values[7],GetValInfoPanel(7),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[7],2); //--- CreateLabel(0,0,pos_prop_names[8],"Volume :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[8],2); CreateLabel(0,0,pos_prop_values[8],GetValInfoPanel(8),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[8],2); //--- CreateLabel(0,0,pos_prop_names[9],"Stop Loss :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[9],2); CreateLabel(0,0,pos_prop_values[9],GetValInfoPanel(9),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[9],2); //--- CreateLabel(0,0,pos_prop_names[10],"Take Profit :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[10],2); CreateLabel(0,0,pos_prop_values[10],GetValInfoPanel(10),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[10],2); //--- CreateLabel(0,0,pos_prop_names[11],"Time :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[11],2); CreateLabel(0,0,pos_prop_values[11],GetValInfoPanel(11),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[11],2); //--- CreateLabel(0,0,pos_prop_names[12],"Identifier :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[12],2); CreateLabel(0,0,pos_prop_values[12],GetValInfoPanel(12),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[12],2); //--- CreateLabel(0,0,pos_prop_names[13],"Type :",anchor,corner,font_name,font_size,font_color,x_first_column,y_prop_array[13],2); CreateLabel(0,0,pos_prop_values[13],GetValInfoPanel(13),anchor,corner,font_name,font_size,font_color,x_second_column,y_prop_array[13],2); //--- ChartRedraw(); // Redraw the chart }
SetInfoPanel() 함수를 자세히 살펴보겠습니다. 그래픽 개체의 속성과 관련된 변수(좌표, 색상, 글꼴, 표시되는 텍스트 등)는 함수 시작 부분에 선언됩니다. 정보 패널의 포지션 속성 목록에 대한 Y 좌표 배열을 채우는 과정에 주의하세요. 초보자도 알기 쉽게 구현되어 있습니다. 그러나 루프를 사용할 때는 몇 줄의 코드로 줄일 수 있습니다. 다음과 같이 작성할 수 있습니다.
//--- Fill the array with coordinates for each line on the info panel for(int i=0; i<INFOPANEL_SIZE; i++) { if(i==0) y_prop_array[i]=y_property; else y_prop_array[i]=y_property+line_height*i; }
그런 다음 패널에 표시되어야 하는 개체의 모든 속성은 이전에 생성된 CreateLabel() 및 CreateEdit() 함수의 매개변수에 지정되어야 합니다 (한 번에 하나의 개체를 요함). 전체 목록은 루프를 사용하여 몇 줄의 코드로 구현할 수도 있습니다. 이렇게 하려면 차트에서 포지션 속성 이름의 텍스트를 표시하는 개체에 대한 또 다른 배열을 만들어야 합니다. 이건 당신의 숙제가 될 겁니다.
개체 번호를 수신하는 GetPropertyValue() 함수는 값을 반환하고 이 값은 CreateLabel() 함수에 네 번째 매개변수(표시된 텍스트)로 전달됩니다. 이것은 포지션 속성 값을 표시할 모든 개체와 관련이 있습니다. 함수에 의해 반환된 값은 조정된 문자열 값이며 궁극적으로 패널에 표시됩니다. 아래는 이 코드입니다.
//+------------------------------------------------------------------+ //| RETURNING THE STRING WITH POSITION PROPERTY VALUE | //+------------------------------------------------------------------+ string GetPropertyValue(int number) { //--- Sign indicating the lack of an open position or a certain property // E.g. the lack of a comment, Stop Loss or Take Profit string empty="-"; //--- If an open position exists, return the value of the requested property if(pos_open) { switch(number) { case 0 : return(pos_symbol); break; case 1 : return(IntegerToString((int)pos_magic)); break; //--- return the value of the comment, if any, otherwise return the sign indicating the lack of comment case 2 : return(pos_comment!="" ? pos_comment : empty); break; case 3 : return(DoubleToString(pos_swap,2)); break; case 4 : return(DoubleToString(pos_commission,2)); break; case 5 : return(DoubleToString(pos_price,_Digits)); break; case 6 : return(DoubleToString(pos_cprice,_Digits)); break; case 7 : return(DoubleToString(pos_profit,2)); break; case 8 : return(DoubleToString(pos_volume,2)); break; case 9 : return(pos_sl!=0.0 ? DoubleToString(pos_sl,_Digits) : empty); break; case 10 : return(pos_tp!=0.0 ? DoubleToString(pos_tp,_Digits) : empty); break; case 11 : return(TimeToString(pos_time,TIME_DATE|TIME_MINUTES)); break; case 12 : return(IntegerToString((int)pos_id)); break; case 13 : return(PositionTypeToString(pos_type)); break; default : return(empty); } } //--- // If there is no open position, return the sign indicating the lack of the open position "-" return(empty); }
위의 코드는 열린 포지션이 있는 경우 함수에 전달된 모든 숫자에 대해 특정 값이 준비됨을 나타냅니다. 현재 열려 있는 포지션이 없는 경우 이 함수는 포지션 속성 값과 관련된 모든 개체에 대해 표시된 대시(-)를 반환합니다.
SetInfoPanel() 함수의 끝에서 강제 차트 다시 그리기를 위해 설계된 ChartRedraw() 함수를 호출합니다. 호출하지 않으면 변경된 내용을 볼 수 없습니다.
이제 Expert Advisor에서 생성한 모든 그래픽 개체를 삭제하는 함수를 작성해야 합니다. DeleteInfoPanel()이라고 합시다.
//+------------------------------------------------------------------+ //| DELETING THE INFO PANEL | //+------------------------------------------------------------------+ void DeleteInfoPanel() { DeleteObjectByName("InfoPanelBackground"); // Delete the panel background DeleteObjectByName("InfoPanelHeader"); // Delete the panel header //--- Delete position properties and their values for(int i=0; i<INFOPANEL_SIZE; i++) { DeleteObjectByName(pos_prop_names[i]); // Delete the property DeleteObjectByName(pos_prop_values[i]); // Delete the value } //--- ChartRedraw(); // Redraw the chart }
이제 MQL5 Wizard에서 템플릿을 생성한 후 템플릿에 원래 존재했던 Expert Advisor의 주요 기능 중에서 생성한 메소드를 배포하기만 하면 됩니다. 이것은 가장 쉬운 부분입니다.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Get the properties and set the panel GetPositionProperties(); //--- return(0); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Print the deinitialization reason to the journal Print(GetDeinitReasonText(reason)); //--- When deleting from the chart if(reason==REASON_REMOVE) //--- Delete all objects relating to the info panel from the chart DeleteInfoPanel(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Get the properties and update the values on the panel GetPositionProperties(); } //+------------------------------------------------------------------+
당신이 우연히 발견할 수 있는 유일한 것은 초기화 해제 이유 코드의 텍스트 설명을 반환하는 GetDeinitReasonText() 함수입니다.
//+---------------------------------------------------------------------+ //| RETURNING A TEXTUAL DESCRIPTION OF THE DEINITIALIZATION REASON CODE | //+---------------------------------------------------------------------+ string GetDeinitReasonText(int reason_code) { string text=""; //--- switch(reason_code) { case REASON_PROGRAM : // 0 text="The Expert Advisor has stopped working calling the ExpertRemove() function."; break; case REASON_REMOVE : // 1 text="The '"+EXPERT_NAME+"' program has been removed from the chart."; break; case REASON_RECOMPILE : // 2 text="The '"+EXPERT_NAME+"' program has been recompiled."; break; case REASON_CHARTCHANGE : // 3 text="Chart symbol or period has been changed."; break; case REASON_CHARTCLOSE : // 4 text="The chart is closed."; break; case REASON_PARAMETERS : // 5 text="Input parameters have been changed by the user."; break; case REASON_ACCOUNT : // 6 text="A different account has been activated."; break; case REASON_TEMPLATE : // 7 text="A different chart template has been applied."; break; case REASON_INITFAILED : // 8 text="A flag specifying that the OnInit() handler returned zero value."; break; case REASON_CLOSE : // 9 text="The terminal has been closed."; break; default : text="The reason is undefined."; } //--- return text; }
현재 열린 포지션이 없는 차트 기호에서 Expert Advisor를 사용하려고 하면 패널에 포지션 속성 값 대신 대시가 표시됩니다. 특정 포지션을 닫은 후에도 패널은 동일하게 보입니다.
그림. 2. 열린 자리가 없는 경우의 정보 패널
오픈 포지션이 있는 심볼의 차트에 Expert Advisor가 추가되거나 Expert Advisor를 차트에 추가한 후 포지션이 열리면 모든 대시가 적절한 포지션 속성 값으로 대체됩니다.
그림 3. 열린 포지션의 속성을 표시하는 정보 패널.
작은 특이점이 하나 있습니다. 포지션을 닫은 후 패널의 값이 업데이트되는 것은 새 틱이 될 때까지가 아닙니다. 값을 즉시 업데이트하는 방법이 있지만 이를 구현하기 위해 수행해야 하는 작업은 다음 시리즈 글에서 설명합니다.
결론
이 글에서 소개된 일부 기능은 MQL5 Cookbook 시리즈의 다음 글에서도 사용될 것이며, 나머지는 당면한 작업에 따라 수정 및 개선될 것입니다. 각각의 새로운 글은 이전 글의 논리적 연속이므로 글을 순서대로 차례로 읽는 것이 좋습니다. 그것은 확실히 당신의 능력과 기술의 수준에 달려 있으므로 더 최근 출판물부터 시작하는 것이 더 합리적이고 흥미로울 수 있습니다.
소스 코드 파일은 글에 첨부되어 있습니다.
MetaQuotes 소프트웨어 사를 통해 러시아어가 번역됨.
원본 기고글: https://www.mql5.com/ru/articles/641



