MQL5 Cookbook:カスタム情報パネル上のポジションプロパティ
はじめに
今回は、現在シンボルについてポジションプロパティを取得し、マニュアルトレーディングの間カスタム情報パネルにそのポジションプロパティを表示するシンプルな Expert Advisor を作成します。情報パネルはグラフィカルオブジェクトを用いて作成され、表示される情報はティック毎にリフレッシュされます。これは "MQL5 Cookbook: Getting 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)とは別に、主要な関数が3個あります。:OnInit()、OnDeinit()、OnTick()です。
OnInit() 関数はプログラムをロード、外部パラメータを変更、プログラムをコンパイル、プログラムがそのときチャートに追加されるならシンボルや期間を変更するときに呼ばれます。必要ならば、のちに連携することができるようにこの関数の特定の変数や配列を初期化することができます。
OnDeinit() 関数はチャートからプログラムを削除するとき、アカウント、シンボル、期間を変更するときに呼ばれます。再初期化理由となる可能性のあるものはすべて MQL5 参照資料にあります。この Expert Advisor はユーザー定義関数GetDeinitReasonText() を採用します。これは再初期化理由識別子( OnDeinit()関数パラメータ)をテキストに変換します。
そして最後に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
変数のあと、グラフィカルオブジェクト名の配列を宣言します。これらオブジェクトはポジションプロパティとその値をチャート上に表示します。このため、文字列配列を2つ作成し、すぐに値に対してそのエレメントを初期化します。カギカッコ内でプログラム冒頭で宣言した定数 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()です。またオブジェクトプロパティの設定も必要なので、オブジェクト自体が複数回作成される一方で、コード1行に実装することのできる便利で手軽な方法を考える方がよいでしょう。
情報パネルの背景とヘッダを作成するにはグラフィカルオブジェクト編集を使用していきます。まず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)はコード1行を用いて作成することができます。チャート上に情報パネルを設定する関数を作成する際例を用いて説明します。
これからポジションプロパティのリストおよびその値を表示するのに使うテキストラベルオブジェクトの作業を続け、同様の方法で 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() 関数を呼ぶ必要はありません。
そしてオープンポジションがあれば、そのプロパティを取得します。なければ全変数はゼロ設定となります。シンプルな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() で指定する必要があります。その際一度に取るオブジェクトは1個です。リスト全体はまたループを使って数行のコードで実装することが可能です。このためにチャート上のポジションプロパティ名のテキストを表示するオブジェクト用の配列を別にもうひとつ作成する必要があります。が、これはみなさんの宿題といたしましょう。
オブジェクト数を受け取る GetPropertyValue() 関数はそのあと4番目のパラメータ(表示されるテキスト)として 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 ウィザードで作成したあとテンプレートに元々あった 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 Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/641
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索