
グラフィカルインタフェ-スを備えたエキスパ-トアドバイザ:パネルの作成(第1部)
目次
概論
algotradeが積極的に開発されているにもかかわらず、多くのトレーダーは依然として手動取引を好んでいます。しかし、ここでは、日常的な操作の自動化は避けることができないと思います。
この記事では、手動取引のためのマルチシンボルシグナルエキスパートアドバイザーの作成について説明します。一例として、端末標準配信のインジケータシグナルStochasticから見てみましょう。このコードは、グラフィカルインターフェイスを使用して独自のエキスパートを作成するために使用できます。他のインジケータに接続したり、特定の計算結果を使用して意思決定を行うことができます。
顧客からの注文を受け付けている人にとっては、この記事は、顧客にデモンストレーションするための技術的タスクの例として役立ちます。またこの例は、グラフィカルインタフェースを持つプログラムを理解できるプログラマーのために、プログラム仕様をコンパイルする時間を短縮するのに役立つかもしれません。
ここで詳細する問題をリストアップしましょう。
- グラフィカルインタフェースの作成。
- 指定されたプロパティを持つ文字のリストの取得。
- 取引操作管理の要素。
- エキスパートを再初期化することなく、チャート上のシンボルとタイムフレームを高速で切り替える。
- ユーザーインターフェイスを使用したチャートのプロパティ管理。
- 色の表示を伴うシンボルのセットからのインジケータシグナルの受信。
- オープンポジションの処理。
- EasyAndFastライブラリの更新。
この記事は2つの部に分かれて掲載されます。この記事では、パネルの作成を見ていき、次の部では、その機能について説明します。
グラフィカルインタフェースの要素
エキスパートの開発は、ユーザーとのやりとりやデータの視覚化を実現するグラフィカルインターフェイスの構築から始まります。標準ライブラリの機能を使用してグラフィカルインタフェースを作成できますが、私の例ではEasyAndFastライブラリに基づいて実装されます。その豊富な機能により、グラフィック部分のリビジョンに気を取られることなく、プログラム自体の機能に集中することができます。
まず、グラフィカルインタフェースの一般的なスキームの概要を説明します。下の図は、GUIウィンドウに2つのタブのグループがあることを示しています。リストには、それらに配置する必要がある機能が表示されます。これは単純化された例であり、発注者と実行者は議論を行い、より詳細に作成することもできます。
図 1. 説明付きグラフィカルインターフェースの一般図。
多くのGUIコントロールがあります。したがって、最初に階層的な形式でそれらをリストアップします。
- コントロール要素のフォーム
- 追加の要約情報を表示するためのステータスバー
- タブグループ:
- Trade:
- 文字のリストをフィルタリングするためのチェックボックス付きの入力フィールド
- 文字のリストの収集を開始するリクエストボタン
- 取引操作SELLのボタン
- 取引操作BUYのボタン
- トランザクションのボリュームを設定する入力フィールド
- 開いているすべてのポジションを閉じるボタン
- SELL用シグナルのレベル設定の入力フィールド
- BUY用シグナルのレベル設定の入力フィールド
- トレードシンボルテーブル
- これらのシンボルを視覚化するためのチャート便宜上、次の要素グループの助けを借りてグラフのいくつかのプロパティを管理できるようにしましょう:
- タイムフレームの切り替えを選択するためのドロップダウンリスト付きコンボボックス
- タイムラインをオン/オフするためのチェックボックス
- 価格スケールのオン/オフを切り替えるためのチェックボックス
- スケールを制御する入力フィールド
- インデントボタン
- インジケータ表示のチェックボックス
- Positions:
- ポジションテーブル
- フレームを再生するプロセスを実行するインジケータ
プログラムのメインクラス(CProgram)は、上記の要素のクラスのメソッドとインスタンスを宣言します。要素を作成するメソッドのコードは別のファイルに入れられ、MQLプログラムのクラスのファイルに接続します。
//+------------------------------------------------------------------+ // |アプリケーションを作成するクラス | //+------------------------------------------------------------------+ class CProgram : public CWndEvents { private: // --- ウィンドウ CWindow m_window1; // --- ステータスバー CStatusBar m_status_bar; // --- タブ CTabs m_tabs1; // --- 入力フィールド CTextEdit m_symb_filter; CTextEdit m_lot; CTextEdit m_up_level; CTextEdit m_down_level; CTextEdit m_chart_scale; // --- ボタン CButton m_request; CButton m_chart_shift; CButton m_buy; CButton m_sell; CButton m_close_all; //--- コンボボックス CComboBox m_timeframes; //--- チェックボックス CCheckBox m_date_scale; CCheckBox m_price_scale; CCheckBox m_show_indicator; // --- 表 CTable m_table_positions; CTable m_table_symb; //--- 標準チャート CStandardChart m_sub_chart1; // --- 実行インジケータ CProgressBar m_progress_bar; //--- public: // --- グラフィカルインタフェースを作成する bool CreateGUI(void); //--- private: // --- フォーム bool CreateWindow(const string text); // --- ステータスバー bool CreateStatusBar(const int x_gap,const int y_gap); // --- タブ bool CreateTabs1(const int x_gap,const int y_gap); // --- 入力フィールド bool CreateSymbFilter(const int x_gap,const int y_gap,const string text); bool CreateLot(const int x_gap,const int y_gap,const string text); bool CreateUpLevel(const int x_gap,const int y_gap,const string text); bool CreateDownLevel(const int x_gap,const int y_gap,const string text); bool CreateChartScale(const int x_gap,const int y_gap,const string text); // --- ボタン bool CreateRequest(const int x_gap,const int y_gap,const string text); bool CreateChartShift(const int x_gap,const int y_gap,const string text); bool CreateBuy(const int x_gap,const int y_gap,const string text); bool CreateSell(const int x_gap,const int y_gap,const string text); bool CreateCloseAll(const int x_gap,const int y_gap,const string text); //--- コンボボックス bool CreateComboBoxTF(const int x_gap,const int y_gap,const string text); //--- チェックボックス bool CreateDateScale(const int x_gap,const int y_gap,const string text); bool CreatePriceScale(const int x_gap,const int y_gap,const string text); bool CreateShowIndicator(const int x_gap,const int y_gap,const string text); // --- 表 bool CreatePositionsTable(const int x_gap,const int y_gap); bool CreateSymbolsTable(const int x_gap,const int y_gap); //--- 標準チャート bool CreateSubChart1(const int x_gap,const int y_gap); // --- 実行インジケータ bool CreateProgressBar(const int x_gap,const int y_gap,const string text); }; //+------------------------------------------------------------------+ // |コントロール要素を作成するメソッド | //+------------------------------------------------------------------+ #include "CreateGUI.mqh" //+------------------------------------------------------------------+
次に、GUIのアセンブリ、要素の作成方法、およびそのプロパティについて詳しく見ていきます。
GUIを構築する
さて、開発されたアプリケーションのグラフィカルインタフェースには、10種類の要素が使用されます。
- コントロール要素のフォーム(CWindow)
- ステータス文字列(CStatusBar)
- タブグループ(CTabs)
- 入力フィールド(CTextEdit)
- ボタン(CButton)
- ドロップダウンリスト付きコンボボックス(CComboBox)
- チェックボックス(CCheckBox)
- 表(CTable)
- 標準チャート(CStandardChart)
- 進捗インジケータ(CProgressBar)
このリストにはいくつかの要素がありますので、各グループを1つずつ見ていきましょう。同じ順序で、それらを作成する方法を紹介します。
コントロール要素のフォーム
以下は、他のすべての要素が配置されるフォームを作成するためのメソッドコードです。始めにプログラムのGUI要素のリストにフォームを追加する必要があります。これを行うには、すCWndContainer :: AddWindow()メソッドを呼び出し、CWindow型の要素のオブジェクトを渡す必要があります。それから、フォームを作成する前に、このプロパティを設定します。以下のプロパティを設定します(以下のリストと同じ順番で)。
- フォームの寸法(幅と高さ)
- タイトルのフォントサイズ
- フォームを移動するモード(チャート内)
- フォームのサイズを手動で変更するモード(枠線をドラッグする)
- フォームのボタン各ボタンの表示は個別にオンになります。この場合、次のことが関係します。
- フォームを閉じる。プログラムのメインフォームで、このボタンをクリックすると、プログラムが閉じられているかどうかを確認するダイアログボックスが表示されます。
- フォームの折りたたみと展開。
- ツールのヒント。このボタンにも2つの状態があります。押された場合に、ヒントが表示されます(設定されている場合)。
- フォームをターミナルグラフの全領域に展開。フォームを展開したら、このボタンを再度クリックして前のサイズに戻すことができます。
- フォームボタンごとに、ツールチップを設定。
プロパティが設定されたら、フォーム作成メソッドCWindow :: CreateWindow()を呼び出し、ここに引き渡す必要があります。
- グラフ識別子、
- サブウィンドウグラフィックスの番号、
- ヘッダーテキスト、
- フォームの初期位置座標。
//+------------------------------------------------------------------+ // |コントロールのフォームを作成します。 | //+------------------------------------------------------------------+ bool CProgram::CreateWindow(const string caption_text) { //--- ウィンドウの配列にウィンドウポインタを追加する CWndContainer::AddWindow(m_window1); // ---プロパティ m_window1.XSize(750); m_window1.YSize(450); m_window1.FontSize(9); m_window1.IsMovable(true); m_window1.ResizeMode(true); m_window1.CloseButtonIsUsed(true); m_window1.CollapseButtonIsUsed(true); m_window1.TooltipsButtonIsUsed(true); m_window1.FullscreenButtonIsUsed(true); // --- ツールチップを設定する m_window1.GetCloseButtonPointer().Tooltip("Close"); m_window1.GetTooltipButtonPointer().Tooltip("Tooltips"); m_window1.GetFullscreenButtonPointer().Tooltip("Fullscreen"); m_window1.GetCollapseButtonPointer().Tooltip("Collapse/Expand"); // ---フォームを作成する if(!m_window1.CreateWindow(m_chart_id,m_subwin,caption_text,1,1)) return(false); //--- return(true); }
GUIの新しい要素をコードに追加するたびに、プログラムをコンパイルし、その結果がどうなるかを確認することが望ましいです。
図2. コントロールのフォーム
以下はすべての中間結果のスクリーンショットです。
ステータス文字列
ステータス行を作成するためのメソッドコードは、メイン要素の設定から始まります。そこから、それに結び付けられた要素のサイズに対する位置合わせと位置づけが計算されます。これにより、アプリケーションを開発するときの時間が節約されます。関連する要素のグループ全体を移動し、主なものの座標のみを変更することができます。要素をバインドするには、そのポインタをCElement :: MainPointer()メソッドに渡します。この例では、ステータスバーをフォームにバインドするので、メソッドにフォームオブジェクトを渡します。
次に、ステータス行のプロパティを設定します。その中で私たちはユーザーの情報が表示される3つのポイントを作ります。
- フォームに対したサイズを指定しないようにするため、フォームの幅が変更されたときに自動的に幅が変更されるようにします。
- フォームの右端からの要素の右端のインデントは1ピクセルになります。
- ステータスバーをフォームの下部に接続すると、形状の高さが変わると自動的に下端に調整されます。
- 次に、項目を追加するときは、幅ごとに指定をします。
プロパティが設定されたら、要素を作成します。これで作業の準備が整い、実行時にその段落のテキストを変更できます。この例ではテキストの最初の段落に『ヘルプが必要な場合、F1キーを押す』を設定します。
メソッドの終わりに、作成した項目のインデックスをGUIエレメントの一般的なリストに保存する必要があります。これを行うには、CWndContainer :: AddToElementsArray()メソッドを呼び出し、フォームのインデックスと要素のオブジェクトを渡します。1つのフォームしかないので、インデックスは0になります。
//+------------------------------------------------------------------+ // | ステータス行を作成します。 | //+------------------------------------------------------------------+ bool CProgram::CreateStatusBar(const int x_gap,const int y_gap) { #define STATUS_LABELS_TOTAL 3 //--- ウィンドウにポインタを保存する m_status_bar.MainPointer(m_window1); // ---プロパティ m_status_bar.AutoXResizeMode(true); m_status_bar.AutoXResizeRightOffset(1); m_status_bar.AnchorBottomWindowSide(true); // --- いくつの部分が必要かを指定して、プロパティを設定します int width[STATUS_LABELS_TOTAL]={0,200,110}; for(int i=0; i<STATUS_LABELS_TOTAL; i++) m_status_bar.AddItem(width[i]); // --- コントロール要素を作成します if(!m_status_bar.CreateStatusBar(x_gap,y_gap)) return(false); // --- ステータスバーの項目にテキストを設定する m_status_bar.SetValue(0,"For Help, press F1"); // --- オブジェクトグループの一般配列にオブジェクトを追加します CWndContainer::AddToElementsArray(0,m_status_bar); return(true); }
EasyAndFastライブラリの残りの要素も同じ原則で作成されます。したがって、以下はエキスパートアドバイザーに使用する、指定プロパティのみを見ていきます。
図3.ステータス行の追加
タブグループ
タブグループを作成するメソッドの中に、以下のプロパティを要素に設定します。
- タブのテキストを中央に配置。
- 作業領域の上部にタブを配置。
- サイズは主要素(フォーム)の領域に自動的に調整される。この場合、タブグループ領域のサイズを指定する必要はありません。
- 主要素の右端と下端をインデントします。フォームのサイズを変更すると、これらのインデントは保存されます。
- 次のタブを追加すると、タブ名と幅もメソッドに転送されます。
メソッドコードは次のとおりです。
//+------------------------------------------------------------------+ // |タブ1のグループを作成します。 | //+------------------------------------------------------------------+ bool CProgram::CreateTabs1(const int x_gap,const int y_gap) { #define TABS1_TOTAL 2 // ---ポインタをメインの要素に保存します m_tabs1.MainPointer(m_window1); // ---プロパティ m_tabs1.IsCenterText(true); m_tabs1.PositionMode(TABS_TOP); m_tabs1.AutoXResizeMode(true); m_tabs1.AutoYResizeMode(true); m_tabs1.AutoXResizeRightOffset(3); m_tabs1.AutoYResizeBottomOffset(25); // ---指定されたプロパティを持つタブを追加する string tabs_names[TABS1_TOTAL]={"Trade","Positions"}; for(int i=0; i<TABS1_TOTAL; i++) m_tabs1.AddTab(tabs_names[i],100); // --- コントロール要素を作成します if(!m_tabs1.CreateTabs(x_gap,y_gap)) return(false); // --- オブジェクトグループの一般配列にオブジェクトを追加します CWndContainer::AddToElementsArray(0,m_tabs1); return(true); }
図4.タブのグループを追加する。
入力フィールド
例として、ユーザが通貨および/または通貨ペアを指定して表内のシンボルリストを作成できる入力フィールドを見ていきます。その主な要素はタブのグループになります。ここでは、この入力フィールドを表示するタブも指定する必要があります。これを行うには、 CTabs :: AddToElementsArray()メソッドを呼び出し、タブのインデックスと添付された要素のオブジェクトを渡します。
次に、この入力フィールドに設定されているプロパティを見ていきます。
- デフォルトでは、テキスト "USD"が入力欄に入力されています。プログラムはUSDがある表のシンボルを収集します。この入力フィールドには、通貨や記号をコンマで区切って指定します。以下では、この入力フィールドのコンマで区切られた行に従って文字のリストを形成する方法を示します。
- 入力フィールドにはチェックボックスが付きます。チェックボックスをオフにすると、入力フィールドのテキストは無視され、見つかったすべての通貨ペアがシンボルのリストに含まれます。
- 入力フィールドの幅はメイン要素の幅全体になり、タブエリアの幅を変更すると修正されます。
- 入力フィールドの右側にはRequestが配置されます。プログラムが実行されている間、入力フィールドに他の通貨や記号を指定することができます。また、リストを作成するには、このボタンをクリックする必要があります。入力フィールドの幅を自動的に変更することを意図しているので、Requestボタンのその右に常になければならないmので、入力フィールドの右側に常にメイン要素の右端からインデントがある必要があります。
要素タイプCTextEditは他のいくつかの要素で構成されています。したがって、プロパティを変更する必要がある場合は、そこへのポインタを取得できます。私達はいくつかのテキスト入力フィールドのプロパティ(CTextBox)を変更する必要があります。以下のコードリストで実装されているのと同じ順序でこれを見てい行きましょう。
- メイン要素の左端からの入力フィールドのインデント(CTextEdit)。
- メイン要素に対する幅の自動変更。
- 入力フィールドがアクティブになると(入力フィールド上でマウスの左ボタンをクリックすると)、テキストは完全に自動的に割り当てられ、迅速に置換することができます。
- 入力フィールドにテキストがまったくない場合は、『EURUSD、GBP、NOK』といったプロンプトが表示されます。
デフォルトでは、入力フィールドのチェックボックスが有効になっています。これを行うには、 アイテムが作成された直後にアクティベートする必要があります。
//+------------------------------------------------------------------+ // | 『Symbols filter』入力フィールドのチェックボックスを作成します。 | //+------------------------------------------------------------------+ bool CProgram::CreateSymbolsFilter(const int x_gap,const int y_gap,const string text) { // ---ポインタをメインの要素に保存します m_symb_filter.MainPointer(m_tabs1); // ---タブに固定します m_tabs1.AddToElementsArray(0,m_symb_filter); // ---プロパティ m_symb_filter.SetValue("USD"); // "EUR,USD" "EURUSD,GBPUSD" "EURUSD,GBPUSD,AUDUSD,NZDUSD,USDCHF" m_symb_filter.CheckBoxMode(true); m_symb_filter.AutoXResizeMode(true); m_symb_filter.AutoXResizeRightOffset(90); m_symb_filter.GetTextBoxPointer().XGap(100); m_symb_filter.GetTextBoxPointer().AutoXResizeMode(true); m_symb_filter.GetTextBoxPointer().AutoSelectionMode(true); m_symb_filter.GetTextBoxPointer().DefaultText("Example: EURUSD,GBP,NOK"); // --- コントロール要素を作成します if(!m_symb_filter.CreateTextEdit(text,x_gap,y_gap)) return(false); // --- チェックボックスをオンにする m_symb_filter.IsPressed(true); // --- オブジェクトグループの一般配列にオブジェクトを追加します CWndContainer::AddToElementsArray(0,m_symb_filter); return(true); }
テキスト入力フィールドに加えて、グラフィカルインタフェースに数字のフィールドがあります。例えば、入力フィールドLot(ポジションを開くときのボリューム)です。このタイプの入力フィールドでは、他のプロパティを指定する必要があります。
- 要素の合計幅。
- 入力する最大値。
- 入力する最小値。
- インクリメントボタンとデクリメントボタンで切り替えるときのステップ。
- 小数点以下の桁数。
- 入力フィールドを数値にするには、これをCTextEdit :: SpinEditMode()メソッドを使用して指定する必要があります。
- 端末のチャートへのプログラムのダウンロード後のデフォルト値。
- 入力フィールドの幅。
- クリック時の入力フィールドでのテキストの自動選択。
- 入力フィールドの要素の右端に配置。
このメソッドのコードは次のとおりです。
//+------------------------------------------------------------------+ // | 入力フィールド "Lot"を作成します。 | //+------------------------------------------------------------------+ bool CProgram::CreateLot(const int x_gap,const int y_gap,const string text) { // ---ポインタをメインの要素に保存します m_lot.MainPointer(m_tabs1); // ---タブに固定します m_tabs1.AddToElementsArray(0,m_lot); // ---プロパティ m_lot.XSize(80); m_lot.MaxValue(1000); m_lot.MinValue(0.01); m_lot.StepValue(0.01); m_lot.SetDigits(2); m_lot.SpinEditMode(true); m_lot.SetValue((string)0.1); m_lot.GetTextBoxPointer().XSize(50); m_lot.GetTextBoxPointer().AutoSelectionMode(true); m_lot.GetTextBoxPointer().AnchorRightWindowSide(true); // --- コントロール要素を作成します if(!m_lot.CreateTextEdit(text,x_gap,y_gap)) return(false); // --- オブジェクトグループの一般配列にオブジェクトを追加します CWndContainer::AddToElementsArray(0,m_lot); return(true); }
図5.入力フィールドを追加。
画像はあまり論理的に見えませんが、他の要素を追加すると、すべてが適切に機能しています。
ボタン
私たちのエキスパートアドバイザーのグラフィカルインターフェイスにいくつかのボタンを追加します。最も多くの特性を持つもの、すなわち、SELLポジションを開くためのボタンを考えてみましょう。
- ボタンの幅。
- ボタンのテキストは、垂直方向と水平方向の両方で正確にセンタリングされます。
- ボタンの背景色。
- カーソルを置いたときの背景色。
- 左クリックしたときの背景色。
- ボタンのテキストの色。
- カーソルを置いたときのテキストの色。
- 左クリックしたときのテキストの色。
- ボタンフレームの色。
- カーソルを置いたときの境界線の色。
- 左クリックしたときの境界線の色。
同じようなプロパティがBUYボタンでも変更され、指定した背景色のみが異なります。
//+------------------------------------------------------------------+ // | 『SELL』ボタンを作成します。 | //+------------------------------------------------------------------+ bool CProgram::CreateSell(const int x_gap,const int y_gap,const string text) { // ---ポインタをメインの要素に保存する m_sell.MainPointer(m_tabs1); // ---タブに固定します m_tabs1.AddToElementsArray(0,m_sell); // ---プロパティ m_sell.XSize(80); m_sell.IsCenterText(true); m_sell.BackColor(C'255,51,51'); m_sell.BackColorHover(C'255,100,100'); m_sell.BackColorPressed(C'195,0,0'); m_sell.LabelColor(clrWhite); m_sell.LabelColorHover(clrWhite); m_sell.LabelColorPressed(clrWhite); m_sell.BorderColor(clrBlack); m_sell.BorderColorHover(clrBlack); m_sell.BorderColorPressed(clrBlack); // --- コントロール要素を作成します if(!m_sell.CreateButton(text,x_gap,y_gap)) return(false); // --- データベース内の要素へのポインタを追加する CWndContainer::AddToElementsArray(0,m_sell); return(true); }
図6. ボタンを追加する。
ドロップダウンリスト付きコンボボックス
時間枠を変更するために、ドロップダウンリストを持つコンボボックスを作成します。設定するプロパティをリストアップしましょう。
- 要素の合計幅。
- リスト内の項目の数(このケースでは21で、端末内の時間枠の数です)。
- 要素はタブ領域の右側に配置されます。
- ボタンのコンボボックスの幅。
- ボタンは要素の右側に配置されます、
次に、リスト内の各項目に値が割り当てられ、いくつかのプロパティがリストへのポインタによって設定されます。
- マウスのカーソルホバリングして項目を強調表示します。
- 強調表示項目。この場合、18の索引項目となります(時間枠D1)。
このコンボボックスを作成するためのメソッドコードを次に示します。
//+------------------------------------------------------------------+ // | 時間枠を選択するためのコンボボックスを作成します。 | //+------------------------------------------------------------------+ bool CProgram::CreateComboBoxTF(const int x_gap,const int y_gap,const string text) { // --- リスト内のアイテムの総数 #define ITEMS_TOTAL2 21 // --- パネルオブジェクトを渡す m_timeframes.MainPointer(m_tabs1); // ---タブに固定します m_tabs1.AddToElementsArray(0,m_timeframes); // ---プロパティ m_timeframes.XSize(115); m_timeframes.ItemsTotal(ITEMS_TOTAL2); m_timeframes.AnchorRightWindowSide(true); m_timeframes.GetButtonPointer().XSize(50); m_timeframes.GetButtonPointer().AnchorRightWindowSide(true); // --- コンボボックスのリストにアイテムの値を保存する string items_text[ITEMS_TOTAL2]={"M1","M2","M3","M4","M5","M6","M10","M12","M15","M20","M30","H1","H2","H3","H4","H6","H8","H12","D1","W1","MN"}; for(int i=0; i<ITEMS_TOTAL2; i++) m_timeframes.SetValue(i,items_text[i]); // --- リストポインタを取得する CListView *lv=m_timeframes.GetListViewPointer(); // --- リストのプロパティを設定する lv.LightsHover(true); lv.SelectItem(18); // --- コントロール要素を作成します if(!m_timeframes.CreateComboBox(text,x_gap,y_gap)) return(false); // --- データベース内の要素へのポインタを追加する CWndContainer::AddToElementsArray(0,m_timeframes); return(true); }
図7. コンボボックスを追加する。
チェックボックス
チェックボックスは最も簡単な要素です。これは2つの特性を指定すれば十分です。
- 幅。
- メイン要素の右側の位置。
要素を作成した後、 プログラムでチェックボックスをオンにすることができます。
//+------------------------------------------------------------------+ // | 『Date scale』チェックボックスを作成します。 | //+------------------------------------------------------------------+ bool CProgram::CreateDateScale(const int x_gap,const int y_gap,const string text) { //--- ウィンドウにポインタを保存する m_date_scale.MainPointer(m_tabs1); // ---タブに固定します m_tabs1.AddToElementsArray(0,m_date_scale); // ---プロパティ m_date_scale.XSize(70); m_date_scale.AnchorRightWindowSide(true); // --- コントロール要素を作成します if(!m_date_scale.CreateCheckBox(text,x_gap,y_gap)) return(false); // ---チェックボックスを有効にする m_date_scale.IsPressed(true); // --- オブジェクトグループの一般配列にオブジェクトを追加します CWndContainer::AddToElementsArray(0,m_date_scale); return(true); }
図8. チェックボックスを追加する。
表
GUIには2つのテーブルがあります。生成された記号と、ポジションを開くためのシグナルのリストを視覚化するものを見ていきます。これは最初のタブに配置されます。まず、配列の宣言と初期化を行い、表のプロパティを設定します。以下のプロパティを設定します。
- 要素の幅。
- 表のサイズ(列と行の数)。
- 列の幅(値は配列で転送されます)。
- テキストの整形(値は配列で転送されます)。
- セルの端からのテキストのインデント。
- ヘッダーを表示。
- 行を選択する機能。
- 列のサイズを手動で変更し、ヘッダーの境界を取得する機能。
- ゼブラスタイルで書式設定して表示する。
- 主要素に対して垂直方向のサイズを自動的変更。
- 主要素の下端からのインデント。
ヘッダーのテキストは、表の作成後に指定することができます。
//+------------------------------------------------------------------+ // |シンボルテーブルを作成します。 | //+------------------------------------------------------------------+ bool CProgram::CreateSymbolsTable(const int x_gap,const int y_gap) { #define COLUMNS1_TOTAL 2 #define ROWS1_TOTAL 1 // ---ポインタをメインの要素に保存します m_table_symb.MainPointer(m_tabs1); // ---タブに固定します m_tabs1.AddToElementsArray(0,m_table_symb); // --- 列幅の配列 int width[COLUMNS1_TOTAL]={95,58}; // --- 列内のテキスト整形配列 ENUM_ALIGN_MODE align[COLUMNS1_TOTAL]={ALIGN_LEFT,ALIGN_RIGHT}; // --- X軸に沿った列のテキストインデントの配列 int text_x_offset[COLUMNS1_TOTAL]={5,5}; // ---プロパティ m_table_symb.XSize(168); m_table_symb.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL); m_table_symb.ColumnsWidth(width); m_table_symb.TextAlign(align); m_table_symb.TextXOffset(text_x_offset); m_table_symb.ShowHeaders(true); m_table_symb.SelectableRow(true); m_table_symb.ColumnResizeMode(true); m_table_symb.IsZebraFormatRows(clrWhiteSmoke); m_table_symb.AutoYResizeMode(true); m_table_symb.AutoYResizeBottomOffset(2); // --- コントロール要素を作成します if(!m_table_symb.CreateTable(x_gap,y_gap)) return(false); // --- ヘッダーのタイトルを設定する m_table_symb.SetHeaderText(0,"Symbol"); m_table_symb.SetHeaderText(1,"Values"); // --- オブジェクトグループの一般配列にオブジェクトを追加します CWndContainer::AddToElementsArray(0,m_table_symb); return(true); }
2番目の表には、開いているポジションのいくつかのプロパティが表示されます。その10個の列には次のデータが表示されます。
- ポジションシンボル。
- ポジション数。
- すべてのオープンポジションの合計金額。
- ポジションBUYのボリューム。
- ポジションSELLのボリューム。
- すべてのオープンポジションの現在の合計。
- 開いているすべてのBUYポジションの現在の結果。
- 開いているすべてのSELLポジションの現在の結果。
- 各シンボルのデポジットのダウンロードは別々に行う。
- 平均価格。
2番目の表では、次のプロパティも設定する必要があります。
- セルの右端と上端からの画像をインデント。
- 値をソートする機能。
- 主要素に対して自動的に水平方向にサイズを変更。
- 主要素の右端からインデント。
最初の列のセルに表示されている画像は、ボタンをクリックすると指定されたシンボル上で、ヘッジアカウントの場合はポジションまたはすべてのポジションを閉じることができます。
//+------------------------------------------------------------------+ // | アイテムのテーブルを作成します。 | //+------------------------------------------------------------------+ bool CProgram::CreatePositionsTable(const int x_gap,const int y_gap) { ... // ---プロパティ m_table_positions.TableSize(COLUMNS2_TOTAL,ROWS2_TOTAL); m_table_positions.ColumnsWidth(width); m_table_positions.TextAlign(align); m_table_positions.TextXOffset(text_x_offset); m_table_positions.ImageXOffset(image_x_offset); m_table_positions.ImageYOffset(image_y_offset); m_table_positions.ShowHeaders(true); m_table_positions.IsSortMode(true); m_table_positions.SelectableRow(true); m_table_positions.ColumnResizeMode(true); m_table_positions.IsZebraFormatRows(clrWhiteSmoke); m_table_positions.AutoXResizeMode(true); m_table_positions.AutoYResizeMode(true); m_table_positions.AutoXResizeRightOffset(2); m_table_positions.AutoYResizeBottomOffset(2); ... return(true); }
図9. 最初のタブに表を追加する。
図10. 2番目のタブに表を追加する。
メインプログラムファイルのテーブルを操作する方法について(CProgram)、私は次の記事の項目で記載したいと思います。
標準チャート
シンボルでデータを視覚化は、CStandardChart型要素が行います。デフォルトでは、毎日の時間枠にEURUSDチャートが表示されます。ここには以下の要素があります。
- 水平スクロール。
- 自動幅調整。
- 自動高さ調整。
- 主要素の右端からインデント。
- 主要素の下端からのインデント。
必要に応じて、水平方向に並べられたグラフの配列を作成することができます。これを行うには、 CStandardChart :: AddSubChart()メソッドを使用して、チャートのシンボルと時間枠を引数として渡します。しかしこの場合、チャートは1つだけ必要で、シンボルと時間枠は他のコントロールを使用して切り替えます。
//+------------------------------------------------------------------+ // | 標準グラフ1を作成する | //+------------------------------------------------------------------+ bool CProgram::CreateSubChart1(const int x_gap,const int y_gap) { //--- ウィンドウにポインタを保存する m_sub_chart1.MainPointer(m_tabs1); // --- タブ1に固定する m_tabs1.AddToElementsArray(0,m_sub_chart1); // ---プロパティ m_sub_chart1.XScrollMode(true); m_sub_chart1.AutoXResizeMode(true); m_sub_chart1.AutoYResizeMode(true); m_sub_chart1.AutoXResizeRightOffset(125); m_sub_chart1.AutoYResizeBottomOffset(2); // ---チャートを追加する m_sub_chart1.AddSubChart("EURUSD",PERIOD_D1); // --- コントロール要素を作成します if(!m_sub_chart1.CreateStandardChart(x_gap,y_gap)) return(false); // --- オブジェクトグループの一般配列にオブジェクトを追加します CWndContainer::AddToElementsArray(0,m_sub_chart1); return(true); }
図11. チャートを追加する。
進捗インジケータ
ユーザがプログラムが現在何をしているのかを理解するために、グラフィカルインタフェースに進捗インジケータを追加します。以下は、この例のプロパティです(コードと同じ順序)。
- 要素の高さの合計。
- インジケータの高さ(進行状況バー)。
- X軸に沿ったインジケータのインデント。
- Y軸に沿ったインジケータのインデント。
- X軸に沿ったメインテキストラベルのインデント。
- Y軸に沿ったメインテキストラベルのインデント。
- X軸に沿ったパーセントテキストラベルのインデント。
- Y軸に沿ったテキストラベルの割合のインデント。
- ドロップダウン項目の属性(自動隠蔽用)。
- フォント。
- インジケータフレームの色。
- インジケータの背景の色。
- インジケータの進行状況バーの色。
- 自動幅調整。
- 主要素の右端からインデント。
以下では、進行状況インジケータの使用例を示します。
//+------------------------------------------------------------------+ // |進行状況バーを作成します。 | //+------------------------------------------------------------------+ bool CProgram::CreateProgressBar(const int x_gap,const int y_gap,const string text) { // ---ポインタをメインの要素に保存します m_progress_bar.MainPointer(m_status_bar); // ---プロパティ m_progress_bar.YSize(17); m_progress_bar.BarYSize(14); m_progress_bar.BarXGap(0); m_progress_bar.BarYGap(1); m_progress_bar.LabelXGap(5); m_progress_bar.LabelYGap(2); m_progress_bar.PercentXGap(5); m_progress_bar.PercentYGap(2); m_progress_bar.IsDropdown(true); m_progress_bar.Font("Consolas"); m_progress_bar.BorderColor(clrSilver); m_progress_bar.IndicatorBackColor(clrWhiteSmoke); m_progress_bar.IndicatorColor(clrLightGreen); m_progress_bar.AutoXResizeMode(true); m_progress_bar.AutoXResizeRightOffset(2); // ---要素を作成する if(!m_progress_bar.CreateProgressBar(text,x_gap,y_gap)) return(false); // --- データベース内の要素へのポインタを追加する CWndContainer::AddToElementsArray(0,m_progress_bar); return(true); }
私たちのエキスパートアドバイザーのグラフィカルインターフェイスで使用されるすべてのコントロールを紹介しました。現時点では、これは単なるグラフィカルシェルです。しかし、私たちは元の考え方に従ってこのすべての作業をするために必要なすべての方法を書いていきます。
EasyAndFastライブラリの更新
EasyAndFast内のCTableクラス内でCTable :: SortData()パブリックメソッドが完成しました。さて、第2引数として、表のソート方向(オプション)を指定することができます。以前は、CTable :: SortData()メソッドの再呼び出しは、現在のものとは逆の方向にソートを開始しました。また、現在のソート方向とソートされた列のインデックスを取得するメソッドが追加されました。ここでは、表がユーザによって手動で(ヘッダをクリックすることによって)ソートされ、表内のデータが同じ順序で更新されていない場合、現在のソート方向を見つけ出してそれを復元することができます。
//+------------------------------------------------------------------+ // | 描画された表を作成するクラス | //+------------------------------------------------------------------+ class CTable : public CElement { public: ... // --- 指定した列でデータをソートする void SortData(const uint column_index=0,const int direction=WRONG_VALUE); // ---(1)現在のソート方向、(2)ソートされた配列のインデックス int IsSortDirection(void) const { return(m_last_sort_direction); } int IsSortedColumnIndex(void) const { return(m_is_sorted_column_index); } ... }; //+------------------------------------------------------------------+ // | 指定した列ごとにデータをソートする | //+------------------------------------------------------------------+ void CTable::SortData(const uint column_index=0,const int direction=WRONG_VALUE) { // ---表の外に出ると終了する if(column_index>=m_columns_total) return; // --- ソートを開始するインデックス uint first_index=0; // ---最後のインデックス uint last_index=m_rows_total-1; // ---ユーザーの方向制御なし if(direction==WRONG_VALUE) { // ---最初の時間は昇順にソートされ、その後は逆の方向にソートされます if(m_is_sorted_column_index==WRONG_VALUE || column_index!=m_is_sorted_column_index || m_last_sort_direction==SORT_DESCEND) m_last_sort_direction=SORT_ASCEND; else m_last_sort_direction=SORT_DESCEND; } else { m_last_sort_direction=(ENUM_SORT_MODE)direction; } // --- 最後にソートされたデータ列のインデックスを記憶する m_is_sorted_column_index=(int)column_index; // --- ソート QuickSort(first_index,last_index,column_index,m_last_sort_direction); }
もう一つの小さな追加がCKeysクラスのCKeys :: KeySymbolメソッドに追加されました。以前は、テンキーパッド(キーボードの右側にある個別のキーブロック)は処理されていませんでした。ここでは、キーボードのこのセクションから数字と特殊文字を入力できます。
//+------------------------------------------------------------------+ // | 押されたキーの文字を返します。 | //+------------------------------------------------------------------+ string CKeys::KeySymbol(const long key_code) { string key_symbol=""; // ---スペースを入力する必要がある場合( "Space"キー) if(key_code==KEY_SPACE) { key_symbol=" "; } // ---アルファベット文字または(2)数字キー文字、または(3)特殊文字を入力する必要がある場合 else if((key_code>=KEY_A && key_code<=KEY_Z) || (key_code>=KEY_0 && key_code<=KEY_9) || (key_code>=KEY_NUMLOCK_0 && key_code<=KEY_NUMLOCK_SLASH) || (key_code>=KEY_SEMICOLON && key_code<=KEY_SINGLE_QUOTE)) { key_symbol=::ShortToString(::TranslateKey((int)key_code)); } // ---シンボルを返す return(key_symbol); }
CTableとCKeysクラスの新バージョンは記事の最後でダウンロードすることができます。
まとめ
この記事の第一部を読んでいただきました。ここでは、私たちは多大な労力を要することなく、複雑なプログラムのためのグラフィカルなインタフェースを作成する方法を分析しました。あなたはこのプログラムを開発して、あなた自身の目的のためにそれを使い続けることができます。この記事の第2部では、グラフィカルインターフェイスの使い方、最も重要な機能の記入方法を紹介します。
以下から記事で紹介したコードをより詳しく知ったりテストを行うために、自分のPCにファイルをダウンロードすることができます。
ファイル名 | コメント |
---|---|
MQL5\Experts\TradePanel\TradePanel.mq5 | グラフィカルインターフェイスによる手動取引のエキスパートアドバイザー |
MQL5\Experts\TradePanel\Program.mqh | プログラムクラスファイル |
MQL5\Experts\TradePanel\CreateGUI.mqh | Program.mqhファイルのプログラムクラスからグラフィカルインターフェイスを作成するための実装方法を含むファイル |
MQL5\Include\EasyAndFastGUI\Controls\Table.mqh | 更新したCTableクラス |
MQL5\Include\EasyAndFastGUI\Keys.mqh | 更新したCKeysクラス |
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/4715





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索