
グラフィカルインタフェースIX:プログレスバーと折れ線グラフコントロール(チャプター2)
コンテンツ
はじめに
このライブラリの目的のより良い理解を得るためには、シリーズ初めのグラフィカルインタフェース I: ライブラリストラクチャの準備(チャプター 1)をお読みください。リンクを含むチャプターのリストは各部の記事の終わりに設けられています。また、そこからはライブラリーの最新のフルバージョンをダウンロードすることもできます。ファイルはアーカイブと同じディレクトリに配置される必要があります。
本稿ではカラーピッカーとカラーボタンというコントロールの2つの相互接続された要素が考察されます。第2章は、インターフェイスのプログレスバーや折れ線グラフコントロールに専念されます。いつものように、これらのコントロールがカスタムMQLアプリケーションでどのように使用できるかを明らかにする詳細な実装例が存在します。
プログレスバーコントロール
長いプロセスの実行中には、インタフェースコントロールが、現在パフォーマンスがどの段階にあり、終了までのおおよその残り時間がどのくらいなのかをユーザに表示することが必要とされます。これは通常、グラフィカルインタフェースのプログレスバーコントロールを用いて達成されます。このコントロールの最も単純な実装は2つの長方形です。そのうちの1つは表示されたプロセスの全体の長さ、あと1つはプロセスの完了割合を表示します。割合は、プログレスバーの様々な実装で頻繁に観察することができ、このコントロールにさらなる情報を追加します。
開発されたライブラリでプログレスバーを作成するために使用されるすべてのコンポーネントを並べてみましょう。
- 背景
- 説明
- インディケータスクロールバー
- インディケータの背景
- 割合
図1 プログレスバーコントロールのコンポーネント
このコントロールを作成するために使用されるクラスを詳しく見てみましょう。
CProgressBarクラスの開発
すべてのコントロールに標準的なメソッドを持つCProgressBarクラスを持ったProgressBar.mqhファイルを作成しライブラリエンジン(WndContainer.mqhファイル)に関連付けます。下記は設定で使用可能なコントロールの一覧です。
- コントロールに共通する背景の色
- 説明テキスト
- 説明テキストの色
- 2軸(x、y)での説明のオフセット
- 領域の色とインディケータの総領域の境界線
- インディケータ領域の背景サイズ
- インディケータ領域の幅の境界
- インディケータスクロールバーの色
- プロセスの実行された割合のラベルオフセット
- パーセンテージの小数点以下の桁数
class CProgressBar : public CElement { private: //--- コントロールの領域 color m_area_color; //--- 表示されたプロセスのテキスト string m_label_text; //--- テキストの色 color m_label_color; //--- 2軸でのテキストラベルのオフセット int m_label_x_offset; int m_label_y_offset; //--- プログレスバーと領域境界の領域の色 color m_bar_area_color; color m_bar_border_color; //--- プログレスバーのサイズ int m_bar_x_size; int m_bar_y_size; //--- 2軸でのプログレスバーのオフセット int m_bar_x_offset; int m_bar_y_offset; //--- プログレスバーの境界の幅 int m_bar_border_width; //--- インディケータの色 color m_indicator_color; //--- 割合のラベルオフセット int m_percent_x_offset; int m_percent_y_offset; //--- 小数点以下の桁数 int m_digits; //--- public: //--- 小数点以下の桁数 void SetDigits(const int digits) { m_digits=::fabs(digits); } //--- (1) 領域の色 (2) ラベルテキストと(3) ラベルの色 void AreaColor(const color clr) { m_area_color=clr; } void LabelText(const string text) { m_label_text=text; } void LabelColor(const color clr) { m_label_color=clr; } //--- テキストラベルのオフセット(ラベルテキスト) void LabelXOffset(const int x_offset) { m_label_x_offset=x_offset; } void LabelYOffset(const int y_offset) { m_label_y_offset=y_offset; } //--- (1) 領域の色 (2) プログレスバーの境界 (3) インディケータの色 void BarAreaColor(const color clr) { m_bar_area_color=clr; } void BarBorderColor(const color clr) { m_bar_border_color=clr; } void IndicatorColor(const color clr) { m_indicator_color=clr; } //--- (1) 境界の色 (2) インディケータ領域のサイズ void BarBorderWidth(const int width) { m_bar_border_width=width; } void BarXSize(const int x_size) { m_bar_x_size=x_size; } void BarYSize(const int y_size) { m_bar_y_size=y_size; } //--- (1) 2軸でのプログレスバーのオフセット (2) パーセンテージラベルのオフセット void BarXOffset(const int x_offset) { m_bar_x_offset=x_offset; } void BarYOffset(const int y_offset) { m_bar_y_offset=y_offset; } //--- テキストラベルのオフセット(プロセスのパーセント) void PercentXOffset(const int x_offset) { m_percent_x_offset=x_offset; } void PercentYOffset(const int y_offset) { m_percent_y_offset=y_offset; } };
プログレスバーコントロールの作成には、5つのプライベートメソッドと1つのパブリックメソッドが必要です。
class CProgressBar : public CElement { private: //--- コントロール作成のためのオブジェクト CRectLabel m_area; CLabel m_label; CRectLabel m_bar_bg; CRectLabel m_indicator; CLabel m_percent; //--- public: //--- コントロール作成メソッド bool CreateProgressBar(const long chart_id,const int subwin,const int x,const int y); //--- private: bool CreateArea(void); bool CreateLabel(void); bool CreateBarArea(void); bool CreateIndicator(void); bool CreatePercent(void); };
プログレスバーが期待通りに動作するためには、インディケータが接続されているプロセスのステップ(反復)の合計数と現在のインデックスを指定する必要があります。CProgressBar::StepsTotal()およびCProgressBar::CurrentIndex()の2つの補助的なメソッドが必要になります。これらはprivate使用のために必要です。唯一の引数は両方のメソッドに送られ、その値は有効範囲の超過を回避するために修正されることがあります。
class CProgressBar : public CElement { private: //--- ステップの総数 double m_steps_total; //--- 現在のインディケータの位置 double m_current_index; //--- private: //--- インディケータの新しい値の設定 void CurrentIndex(const int index); void StepsTotal(const int total); }; //+------------------------------------------------------------------+ //| プログレスバーのステップの総数 | //+------------------------------------------------------------------+ void CProgressBar::StepsTotal(const int total) { //--- 0未満の場合は修正する m_steps_total=(total<1)?1 : total; //--- 範囲外のインデックスを修正する if(m_current_index>m_steps_total) m_current_index=m_steps_total; } //+------------------------------------------------------------------+ //| インディケータの現在の状態 | //+------------------------------------------------------------------+ void CProgressBar::CurrentIndex(const int index) { //--- 0未満の場合は修正する if(index<0) m_current_index=1; //--- 範囲外のインデックスを修正する else m_current_index=(index>m_steps_total)?m_steps_total : index; }
CProgressBar::StepsTotal()とCProgressBar::CurrentIndex()メソッドはメインメソッドで呼ばれ外部のコントロールの CProgressBar::Update()と相互作用します。プログレスバーの必要な計算を実行し再描画するためのパラメータは、このメソッドに送られます。1番目の引数はプロセスの反復インデックス(index)で2番目は反復の総数(total)です。これらの値がすべて確認された後には、インディケータのスクロールバーの新しい幅が計算されます。必要であれば、この値は、後で修正することができます。さらに(1) インディケータのスクロールバーで新しい幅が設定され (2) パーセント値が計算されてその文字列が形成され、メソッドの最後では (3) パーセント値の文字列に新しい値が設定されます。
class CProgressBar : public CElement { public: //--- インディケータを指定された値で更新する void Update(const int index,const int total); }; //+------------------------------------------------------------------+ //| プログレスバーを更新する | //+------------------------------------------------------------------+ void CProgressBar::Update(const int index,const int total) { //--- 新しいインデックスを設定する CurrentIndex(index); //--- 新しい範囲を設定する StepsTotal(total); //--- インディケータの幅を計算する double new_width=(m_current_index/m_steps_total)*m_bar_bg.XSize(); //--- 1未満の場合は修正する if((int)new_width<1) new_width=1; else { //--- 境界幅を考慮して修正する int x_size=m_bar_bg.XSize()-(m_bar_border_width*2); //--- 境界を超えた場合は修正する if((int)new_width>=x_size) new_width=x_size; } //--- インディケータの新しい幅を設定する m_indicator.X_Size((int)new_width); //--- 割合を計算して文字列を形成する double percent =m_current_index/m_steps_total*100; string desc =::DoubleToString((percent>100)?100 : percent,m_digits)+"%"; //--- 新しい値を設定する m_percent.Description(desc); }
プログレスバーの作成および管理メソッドはすべてそろいました。ここではそれを検証して。それがMQLアプリケーションのグラフィカルインターフェースとしてどのように見えるかを確認します。
プログレスバーの検証
前の記事のエキスパートアドバイザーは検証のためにテンプレートとして使用することができます。メインメニューとステータスバーを除いたすべてのコントロールを削除します。このエキスパートアドバイザーのグラフィカルインターフェイスに8つのプログレスバーが追加されます。このタスクをより面白くするために、反復回数の管理にスライダを用います。
CProgramカスタムクラスのボディではコントロールの必要な型のインスタンスとそれらをフォームの端からのオフセットをもって作成するメソッドを宣言します。
class CProgram : public CWndEvents { private: //--- スライダ CSlider m_slider1; //--- プログレスバー CProgressBar m_progress_bar1; CProgressBar m_progress_bar2; CProgressBar m_progress_bar3; CProgressBar m_progress_bar4; CProgressBar m_progress_bar5; CProgressBar m_progress_bar6; CProgressBar m_progress_bar7; CProgressBar m_progress_bar8; //--- private: //--- スライダ #define SLIDER1_GAP_X (7) #define SLIDER1_GAP_Y (50) bool CreateSlider1(const string text); //--- #define PROGRESSBAR1_GAP_X (7) #define PROGRESSBAR1_GAP_Y (100) bool CreateProgressBar1(void); //--- #define PROGRESSBAR2_GAP_X (7) #define PROGRESSBAR2_GAP_Y (125) bool CreateProgressBar2(void); //--- #define PROGRESSBAR3_GAP_X (7) #define PROGRESSBAR3_GAP_Y (150) bool CreateProgressBar3(void); //--- #define PROGRESSBAR4_GAP_X (7) #define PROGRESSBAR4_GAP_Y (175) bool CreateProgressBar4(void); //--- #define PROGRESSBAR5_GAP_X (7) #define PROGRESSBAR5_GAP_Y (200) bool CreateProgressBar5(void); //--- #define PROGRESSBAR6_GAP_X (7) #define PROGRESSBAR6_GAP_Y (225) bool CreateProgressBar6(void); //--- #define PROGRESSBAR7_GAP_X (7) #define PROGRESSBAR7_GAP_Y (250) bool CreateProgressBar7(void); //--- #define PROGRESSBAR8_GAP_X (7) #define PROGRESSBAR8_GAP_Y (275) bool CreateProgressBar8(void); };
すべてのコントロールの作成はすでに以前の記事で考察されたため、一例として、プログレスバーのメソッドコードを表示します(以下のコードを参照)。みられる通り、理解を妨げるものは何もありません。すべてがかなり透明でシンプルです。
//+------------------------------------------------------------------+ //| プログレスバー1が作成される | //+------------------------------------------------------------------+ bool CProgram::CreateProgressBar1(void) { //--- フォームへのポインタを保存する m_progress_bar1.WindowPointer(m_window1); //--- 座標 int x=m_window1.X()+PROGRESSBAR1_GAP_X; int y=m_window1.Y()+PROGRESSBAR1_GAP_Y; //--- 作成前にプロパティを設定する m_progress_bar1.XSize(220); m_progress_bar1.YSize(15); m_progress_bar1.BarXSize(123); m_progress_bar1.BarYSize(11); m_progress_bar1.BarXOffset(65); m_progress_bar1.BarYOffset(2); m_progress_bar1.LabelText("Progress 01:"); //--- コントロールを作成する if(!m_progress_bar1.CreateProgressBar(m_chart_id,m_subwin,x,y)) return(false); //--- ベースでのコントロールにポインタを追加する CWndContainer::AddToElementsArray(0,m_progress_bar1); return(true); }
メソッドの呼び出しはグラフィカルインターフェイスを作成するメインメソッドで行う必要があります。以下は、追加のみを示したこのメソッドの短縮版です。
//+------------------------------------------------------------------+ //| エキスパートパネルを作成する | //+------------------------------------------------------------------+ bool CProgram::CreateExpertPanel(void) { //--- コントロール要素のためのフォームを作成する //--- コントロールの作成 // メインメニュー //--- コンテキストメニュー //--- スライダ if(!CreateSlider1("Iterations total:")) return(false); //--- プログレスバー if(!CreateProgressBar1()) return(false); if(!CreateProgressBar2()) return(false); if(!CreateProgressBar3()) return(false); if(!CreateProgressBar4()) return(false); if(!CreateProgressBar5()) return(false); if(!CreateProgressBar6()) return(false); if(!CreateProgressBar7()) return(false); if(!CreateProgressBar8()) return(false); //--- チャートの再描画 m_chart.Redraw(); return(true); }
ここで動作についてお話ししましょう。 すべてのプログレスバーのプロセスは CProgram::OnTimerEvent()カスタムクラスのタイマーで模倣されます。反復回数は、スライダを使用して手動で制御でき、すべてのタイマーイベントでは編集ボックスで現在の値を取得するためのオプションがあります。各プログレスバーには異なる値で増加する静的カウンターがあります。これによって、バーが非同期的に様々なプロセス内で動作する進行を模倣します。
//+------------------------------------------------------------------+ //| タイマー | //+------------------------------------------------------------------+ void CProgram::OnTimerEvent(void) { CWndEvents::OnTimerEvent(); //--- 反復数 int total=(int)m_slider1.GetValue(); //--- 8のプログレスバー static int count1=0; count1=(count1>=total) ?0 : count1+=8; m_progress_bar1.Update(count1,total); //--- static int count2=0; count2=(count2>=total) ?0 : count2+=3; m_progress_bar2.Update(count2,total); //--- static int count3=0; count3=(count3>=total) ?0 : count3+=12; m_progress_bar3.Update(count3,total); //--- static int count4=0; count4=(count4>=total) ?0 : count4+=6; m_progress_bar4.Update(count4,total); //--- static int count5=0; count5=(count5>=total) ?0 : count5+=18; m_progress_bar5.Update(count5,total); //--- static int count6=0; count6=(count6>=total) ?0 : count6+=10; m_progress_bar6.Update(count6,total); //--- static int count7=0; count7=(count7>=total) ?0 : count7+=1; m_progress_bar7.Update(count7,total); //--- static int count8=0; count8=(count8>=total) ?0 : count8+=15; m_progress_bar8.Update(count8,total); //--- ステータスバーのタイマー static int count9=0; if(count9<TIMER_STEP_MSC*10) { count9+=TIMER_STEP_MSC; return; } count9=0; m_status_bar.ValueToItem(1,::TimeToString(::TimeLocal(),TIME_DATE|TIME_SECONDS)); }
プログラムをコンパイルしてチャートにアップロードします。結果は次の通りです。
図2 プログレスバーコントロールの検証
いいですね!以下では、折れ線グラフのためのテストアプリケーションのより具体的な例でプログレスバーを検証します。
折れ線グラフコントロール
折れ線グラフは、垂直方向と水平方向のスケールを持つ指定された矩形領域内のデータ配列を可視化することができ、点が後に線で接続されます。このようなツールの利点を過小評価することは困難です。例えば、トレーダーの口座のチャート残高と資本の表示が可能です。私の意見では、指標をはじめとする標準タイプのMetaTrader端末プログラムはウィンドウの可視部分のみを使い全体のデータ配列を表示することはできないので、あまり便利ではありません。
端末チャートのスケールは0(最強レベルの圧縮)から 5のみに設定することができます。最強レベルの圧縮とは配列の1つのコントロールのために1画素が選択されることを意味し、データの配列全体が選択された領域に収まらない場合は、チャートのスクロールバーを使用するオプションがあります。より多くのデータを収める2番目の方法は、より高い時間枠に移動することであり、少なくともCandles(ローソク足)やBars(バー)チャートが設定されている場合は、指定した期間の全範囲の値を見ることができます。
チャートスケールが無制限であるのは便利で、任意のサイズのデータを持つ配列を複数のピクセル幅である幅の領域に収めることができます。同時に、データが常に領域の先頭から最後まで正確に位置決めされることが要求されます。すなわちデータ(配列コントロール)の最初の点は領域の左端、最後の点は右橋に固定されなければなりません。例としてExcelのチャートはこのように作成されています。これによって、最小値と最大値を失うことなく、任意のサイズの配列を折れ線グラフ上に収めることができます。
以下のスクリーンショットはExcelの折れ線グラフの例を表示します。ここでは50000コントロールの配列がいかなる欠損(最小値と最大値)もなく収まるように管理されています。
図3 Excelでの折れ線グラフデータ配列のサイズ - 50000コントロール
ターミナル開発者は、標準ライブラリで、いくつかのチャートタイプを作成するクラスを提供してきました。ディレクトリ内の位置は<data folder>\MQLX\Include\Canvas\Chartsです。以下にこれらのクラスを一覧表示します。
- CChartCanvas – 提供された3つのタイプのチャートから1つを作成するための基本クラス
- CLineChart – 線形グラフ作成のためのCChartCanvas の派生クラス
- CHistogramChart – ヒストグラム作成のためのCChartCanvas の派生クラス
- CPieChart – 円線図作成のためのCChartCanvas の派生クラス
チャートがすでにMQLアプリケーションのグラフィカルインターフェースで使用することができるように、今は一時的な解決策として標準ライブラリによって提供されているクラスを適用します。これらのクラスのいくつかのメソッドが変更され、そのうちのいくつかは完全に書き換えられます。追加的なオプションも加えられます。最終的には、今後の記事を書く過程で、より高品質のグラフを描画するための追加的なライブラリの作成を試みます。
標準ライブラリクラスの改善
前述したように、必要なクラスを持つファイルは<data folder>\MQLX\Include\Canvas\Chartsディレクトリに格納されています。開発されたライブラリのディレクトリ(<data folder>\MQLX\Include\EasyAndFastGUI\Canvas)にChartsフォルダを作成して、ChartCanvas.mqhとLineChart.mqhファイルを標準ライブラリからコピーしましょう。
初めにCChartCanvas基本クラスを変更します。この時点での基本クラスはCCanvasです。標準ライブラリのCCanvasクラスのコピーは開発されたライブラリに以前に適応されて名前がCCustomCanvasに変えられました。ここではそれをCChartCanvasの基本クラスにします。下のコードではChartCanvas.mqhファイルで変更された行が示されています。
//+------------------------------------------------------------------+ //| ChartCanvas.mqh | //| Copyright 2009-2016, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "..\CustomCanvas.mqh" ... //+------------------------------------------------------------------+ //| CChartCanvasクラス | //| 用途:グラフィカルチャートの基本クラス | //+------------------------------------------------------------------+ class CChartCanvas : public CCustomCanvas { ...
グラフにグラデーション背景があることが好ましいので、このオプションが追加されます。実装には、色を操作するクラス(CColors)を持つファイルをCustomCanvas.mqhファイルと関連付けます。
//+------------------------------------------------------------------+ //| CustomCanvas.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "..\Colors.mqh" ...
CChartCanvasクラスではこのクラスのインスタンスを宣言してプロジェクトに使用します。
標準ライブラリがゼロから書かれなければならないことを考えると、開発のこの段階で、使用しようとしているクラスメソッドの詳細な説明をする意味がありません。変更が行われたメソッドと追加されたメソッドを簡単に示し、必要な場合にはご自分で比較を行うことができるようにします。
列挙に移りましょう。グラデーション領域の作成には少なくとも2色が必要です。CChartCanvasクラスでは背景色を示すCChartCanvas::ColorBackground()メソッドがすでに存在します。2番目の色の設定のためには似たようなCChartCanvas::ColorBackground2() メソッドが追加されます。CElementsクラスのInitColorArray()メソッド同様、配列をグラデーションの色で初期化するための特別のメソッドです。グラデーションを描画するにはCChartCanvas::DrawBackground()メソッドの変更が必要です。以前にはCCustomCanvas::Erase()を呼び出して背景を1色でぬるので十分で、必要な色は引数として受け渡されましたが、今は(1)配列を宣言しキャンバスの高さにサイズを設定し(2)グラデーションの色でそれを初期化し(3)この配列の色を使用して反復して各ラインを引くことが必要です。配列をゼロにしてオブジェクトを削除するためにはあと1つのCChartCanvas::DeleteAll() メソッドがクラスに追加される必要があります。
CChartCanvasクラスでの他のすべての変更は、シリーズとマーカーのオフセット、フォント、マーカーの大きさ、グリッドスタイルを計算し設定するメソッドに影響を与えます。これらのコードの追加および変更は、標準ライブラリからの最初のバージョンと比較することで、本稿に添付されたファイルで勉強することができます。
さらにCLineChartクラスに影響を与える変更を考察しましょう。CChartCanvasが基本クラスです。ここではオブジェクトを破壊するCLineChart::DeleteAll()メソッドの作成も必要です。主要な変更はCLineChart::DrawData()メソッドによるチャート上でのデータの描画です。初めに、計算を実行するCLineChart::CheckLimitWhile()、CLineChart::CalculateVariables() および CLineChart::CalculateArray() メソッドが追加されました。そして、最も重要なのは、チャート上に表示されるデータの圧縮アルゴリズムが正しいことです。提案されたオプションでは、表示された画素の配列の幅がチャートで選択された領域の幅を超えた場合に、この配列がチャートの右端を越えて延在する画素の数に等しい部分に分割されるように圧縮が行われます。そして(最初の部分以外の)すべての部分が前のものと重なっています。このようにして、右端を超えるオフセットが低減され、配列の右側のコントロールは常に右側に固定されるので、最小値と最大値に関するデータの視覚的な損失はありません。
ここで、以前の関連記事で考慮されたライブラリのすべてのコントロールのクラスに似ている折れ線グラフコントロール作成クラスを作成する必要があります。
CLineGraphクラスの開発
初めにObjects.mqhファイルで新しいオブジェクト型が作成されます。このファイルにあるすべてのクラスに似たCLineChartObjectクラスです。CLineChartが基本クラスで、ファイルはObjects.mqhファイルと関連付けられる必要があります。
//+------------------------------------------------------------------+ //| Objects.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "..\Canvas\Charts\LineChart.mqh" ...
CLineGraphクラスを持つLineGraph.mqhファイルを作成し、ライブラリエンジン(WndContainer.mqh)と関連付けます。他のライブラリコントロール同様、CLineGraphクラスには標準的な仮想メソッドが必要です。
//+------------------------------------------------------------------+ //| 折れ線グラフ作成クラス | //+------------------------------------------------------------------+ class CLineGraph : public CElement { private: //--- コントロールが接続されるフォームへのポインタ CWindow *m_wnd; public: //--- フォームポインタを格納する void WindowPointer(CWindow &object) { m_wnd=::GetPointer(object); } //--- public: //--- チャートイベントの処理 virtual void OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) {} //--- タイマー virtual void OnEventTimer(void) {} //--- コントロールの移動 virtual void Moving(const int x,const int y); //--- (1)表示 (2)非表示 (3)リセット (4)削除 virtual void Show(void); virtual void Hide(void); virtual void Reset(void); virtual void Delete(void); };
下記で折れ線グラフの外観を設定するためのプロパティを一覧表示します。
- 背景のグラデーションの色
- 境界線の色
- グリッドの色
- テキストの色
- 小数点以下の桁数(縦のスケールの値)
class CLineGraph : public CElement { private: //--- グラデーション色 color m_bg_color; color m_bg_color2; //--- 境界線の色 color m_border_color; //--- グリッドの色 color m_grid_color; //--- テキストの色 color m_text_color; //--- 小数点以下の桁数 int m_digits; //--- public: //--- 小数点以下の桁数 void SetDigits(const int digits) { m_digits=::fabs(digits); } //--- グラデーションの2色 void BackgroundColor(const color clr) { m_bg_color=clr; } void BackgroundColor2(const color clr) { m_bg_color2=clr; } //--- (1) 境界 (2) グリッド (3) テキストの色 void BorderColor(const color clr) { m_border_color=clr; } void GridColor(const color clr) { m_grid_color=clr; } void TextColor(const color clr) { m_text_color=clr; } };
折れ線グラフの作成には1つのプライベートと1つのパブリックメソッドが必要です。
class CLineGraph : public CElement { public: //--- コントロール作成メソッド bool CreateLineGraph(const long chart_id,const int subwin,const int x,const int y); //--- private: bool CreateGraph(void); };
そして、最後に、作成後に折れ線グラフを操作するために、下記を可能にするメソッドを使用します。
- グラフの系列の最大数を設定
- 垂直スケールとグリッドの線の量の最大値/最小値を設定
- データ系列を追加
- データ系列をレフレッシュ
- データ系列を削除
class CLineGraph : public CElement { public: //--- 最大データ系列 void MaxData(const int total) { m_line_chart.MaxData(total); } //--- 縦スケールパラメータの設定 void VScaleParams(const double max,const double min,const int num_grid); //--- チャートへの系列の追加 void SeriesAdd(double &data[],const string descr,const color clr); //--- チャートでの系列の更新 void SeriesUpdate(const uint pos,const double &data[],const string descr,const color clr); //--- チャートから系列を削除 void SeriesDelete(const uint pos); };
この最小セットは、MQLアプリケーションでの折れ線グラフの使用には十分です。これから、動作検証のためのアプリケーションを作成します。
折れ線グラフ検証のためのアプリケーションの作成
検証のためには、本稿で既にプログレスバーコントロールの検証に使用されたEAのコピーを作成することができます。ステータスバーを除いたすべてのコントロールを削除します。グラフィカルインターフェースで折れ線グラフを管理するためにどんなコントロール作成する必要があるかを決定します。
系列の配列へのデータの追加と削減が自動的に実行されるモードを実装します。この工程はCProgramユーザークラスのタイマーで制御されます。工程の速さも編集ボックスで示されたミリ秒単位の間隔で制御されるようにしましょう (Delayパラメータ)。このモードのためには2つの追加のコントロールが導入され、編集ボックスに範囲を示すことができます。すなわち、配列での最小(Min. limit sizeパラメータ)と最大(Max. limit sizeパラメータ)数のコントロールです。このモードを有効にすると、タイマーの各イベント上の配列は1つのコントロールによって指定された最大サイズに到達するまで増加されてその後指定された最小に到達するまで減少され、これが最初から繰り返されます。手動でも管理可能な配列の現在のサイズ(Size of seriesパラメータ)は別のコントロールの編集ボックスに表示されます。
系列数(データ系列)はドロップダウンリストからの選択によって1~24に設定できます(Number of seriesパラメータ)。データは、サインとコサインの数学関数の戻り値に基づいて、三角関数の式で計算されます。計算に使われるパラメータの管理のためのコントロールを追加します。ここではそれは (1) 増加率(Increment ratioパラメータ)と (2) 以前のデータ系列についての各系列のオフセット(Offset seriesパラメータ)です。増加率の変更によって系列の様々な可視化を得ることができます。Increment ratio(増加率)パラメータには、モードが有効になっている場合に、反復処理による系列サイズの増加/減少の際のできるだけ早い次の値への自動切り替えを実行するためのチェックボックスがあります。ここでの比率の増加はまたコントロールが最大値に達するまで実行されます。最大値が達成されると、カウンタはIncrement ratioパラメータの値を減らすために反転します。言い換えれば、カウンタは最小値または最大値の制限を達成した後に逆転されます。
この実験をさらに面白くするために、「実行中」の系列のアニメーション作成モードを実装し、また実行速度を制御する追加的なパラメータを追加します。さらに、グラフィカルインターフェースにプログレスバーを追加し、自動的に系列の配列にデータを自動的に追加/削減するモードが有効になっている場合にはプロセスの残り時間が表示されます。
よって、プログラムのグラフィカルインターフェース作成に必要なコントロールクラスインスタンスとそれらを作成するメソッドとフォームの端からのオフセットを宣言します。
class CProgram : public CWndEvents { private: //--- コントロール CSpinEdit m_delay_ms; CComboBox m_series_total; CCheckBoxEdit m_increment_ratio; CSpinEdit m_offset_series; CSpinEdit m_min_limit_size; CCheckBoxEdit m_max_limit_size; CCheckBoxEdit m_run_speed; CSpinEdit m_series_size; CLineGraph m_line_chart; CProgressBar m_progress_bar; //--- private: //--- 折れ線グラフを管理するためのコントロール #define SPINEDIT1_GAP_X (7) #define SPINEDIT1_GAP_Y (25) bool CreateSpinEditDelay(const string text); #define COMBOBOX1_GAP_X (7) #define COMBOBOX1_GAP_Y (50) bool CreateComboBoxSeriesTotal(const string text); #define CHECKBOX_EDIT1_GAP_X (161) #define CHECKBOX_EDIT1_GAP_Y (25) bool CreateCheckBoxEditIncrementRatio(const string text); #define SPINEDIT2_GAP_X (161) #define SPINEDIT2_GAP_Y (50) bool CreateSpinEditOffsetSeries(const string text); #define SPINEDIT3_GAP_X (330) #define SPINEDIT3_GAP_Y (25) bool CreateSpinEditMinLimitSize(const string text); #define CHECKBOX_EDIT2_GAP_X (330) #define CHECKBOX_EDIT2_GAP_Y (50) bool CreateCheckBoxEditMaxLimitSize(const string text); #define CHECKBOX_EDIT3_GAP_X (501) #define CHECKBOX_EDIT3_GAP_Y (25) bool CreateCheckBoxEditRunSpeed(const string text); #define SPINEDIT4_GAP_X (501) #define SPINEDIT4_GAP_Y (50) bool CreateSpinEditSeriesSize(const string text); //--- 折れ線グラフt #define LINECHART1_GAP_X (5) #define LINECHART1_GAP_Y (75) bool CreateLineChart(void); //--- パフォーマンスのインディケータ #define PROGRESSBAR1_GAP_X (5) #define PROGRESSBAR1_GAP_Y (364) bool CreateProgressBar(void); };
カスタムクラスのコントロールを作成するメソッドはすべてすでに以前の記事で考察されています。ここでは折れ線グラフを作成するためのコードが表示されます。しかし、その前には、配列を操作しそれらのデータを計算するためのメソッドを作成する必要があります。表示データのためのdata[] 配列と試算のための追加的なdata_temp[]配列を持ったSeries構造体を宣言します。系列の色と説明のための配列も必要です。
class CProgram : public CWndEvents { private: //--- チャートでの系列の構造体 struct Series { double data[]; // 表示されるデータの配列 double data_temp[]; // 計算のための追加的な配列 }; Series m_series[]; //--- 系列の(1) 名前と (2) 色 string m_series_name[]; color m_series_color[]; };
配列の新しいサイズの設定にはCProgram::ResizeDataArrays()メソッドが使われます。系列の現在の数とサイズもまたコントロールから取得されます。
class CProgram : public CWndEvents { private: //--- 系列の新しいサイズを設定する void ResizeDataArrays(void); }; //+------------------------------------------------------------------+ //| 配列の新しいサイズを設定する | //+------------------------------------------------------------------+ void CProgram::ResizeDataArrays(void) { int total =(int)m_series_total.ButtonText(); int size_of_series =(int)m_series_size.GetValue(); //--- for(int s=0; s<total; s++) { //--- 配列の初期サイズを設定する ::ArrayResize(m_series[s].data,size_of_series); ::ArrayResize(m_series[s].data_temp,size_of_series); } }
サイズの設定後、計算に使用される配列は新しいデータで初期化される必要があります。このためにはCProgram::InitArrays()メソッドを適用します。試算にはOffset series(オフセット系列)とIncrement ratio(増加率)パラメータが使われます。「実行中」系列モードにはm_run_speed_counterカウンタが必要です。タイマーでのCProgram::ShiftLineChartSeries()メソッドの呼び出し時には、カウンタはRun Speed(実行速度)コントロールの編集ボックスのチェックボックスが有効になっている場合にはその値で増加されます。
class CProgram : public CWndEvents { private: //--- 「実行中」系列の速度カウンタ double m_run_speed_counter; //--- 計算のための補助的な配列の初期化 void InitArrays(void); //--- 折れ線グラフの系列のシフト(「実行中」チャート) void ShiftLineChartSeries(void); }; //+------------------------------------------------------------------+ //| コンストラクタ | //+------------------------------------------------------------------+ CProgram::CProgram(void) : m_run_speed_counter(0.0) { //--- ... } //+------------------------------------------------------------------+ //| ラインチャートの系列のシフト | //+------------------------------------------------------------------+ void CProgram::ShiftLineChartSeries(void) { if(m_run_speed.CheckButtonState()) m_run_speed_counter+=m_run_speed.GetValue(); } //+------------------------------------------------------------------+ //| 計算のための補助的な配列の初期化 | //+------------------------------------------------------------------+ void CProgram::InitArrays(void) { int total=(int)m_series_total.ButtonText(); //--- for(int s=0; s<total; s++) { int size_of_series=::ArraySize(m_series[s].data_temp); //--- for(int i=0; i<size_of_series; i++) { if(i==0) { if(s>0) m_series[s].data_temp[i]=m_series[s-1].data_temp[i]+m_offset_series.GetValue(); else m_series[s].data_temp[i]=m_run_speed_counter; } else m_series[s].data_temp[i]=m_series[s].data_temp[i-1]+(int)m_increment_ratio.GetValue(); } } }
例として、エキスパートアドバイザーで外部パラメータで選択できる3つの計算式に基づいた一連の計算をします。このためにENUM_FORMULA列挙が宣言されます。系列の色のパラメータの設定は外部パラメータに移動します(下記のコードを参照)。
//--- 機能の列挙 enum ENUM_FORMULA { FORMULA_1=0, // 数式1 FORMULA_2=1, // 数式2 FORMULA_3=2 // 数式3 }; //--- 外部パラメータ input ENUM_FORMULA Formula =FORMULA_1; // 数式 input color ColorSeries_01 =clrRed; // 色の系列01 input color ColorSeries_02 =clrDodgerBlue; // 色の系列 02 input color ColorSeries_03 =clrWhite; // 色の系列 03 input color ColorSeries_04 =clrYellow; // 色の系列 04 input color ColorSeries_05 =clrMediumPurple; // 色の系列 05 input color ColorSeries_06 =clrMagenta; // 色の系列 06
系列の配列の初期のサイズの設定と系列の説明と色の配列の初期化は CProgramクラスのコンストラクタで行われます。
//+------------------------------------------------------------------+ //| コンストラクタ | //+------------------------------------------------------------------+ CProgram::CProgram(void) : m_run_speed_counter(0.0) { //--- 系列の配列サイズの設定 int number_of_series=24; ::ArrayResize(m_series,number_of_series); ::ArrayResize(m_series_name,number_of_series); ::ArrayResize(m_series_color,number_of_series); //--- 系列名の配列の初期化 for(int i=0; i<number_of_series; i++) m_series_name[i]="Series "+string(i+1); //--- 系列の色の配列の初期化 m_series_color[0] =m_series_color[6] =m_series_color[12] =m_series_color[18] =ColorSeries_01; m_series_color[1] =m_series_color[7] =m_series_color[13] =m_series_color[19] =ColorSeries_02; m_series_color[2] =m_series_color[8] =m_series_color[14] =m_series_color[20] =ColorSeries_03; m_series_color[3] =m_series_color[9] =m_series_color[15] =m_series_color[21] =ColorSeries_04; m_series_color[4] =m_series_color[10] =m_series_color[16] =m_series_color[22] =ColorSeries_05; m_series_color[5] =m_series_color[11] =m_series_color[17] =m_series_color[23] =ColorSeries_06; }
外部パラメータに示された数式に基づいた系列の計算にはCProgram::CalculateSeries()メソッドを使用します。
class CProgram : public CWndEvents { private: //--- 系列を計算する void CalculateSeries(void); }; //+------------------------------------------------------------------+ //| 系列を計算する | //+------------------------------------------------------------------+ void CProgram::CalculateSeries(void) { int total=(int)m_series_total.ButtonText(); //--- for(int s=0; s<total; s++) { int size_of_series=::ArraySize(m_series[s].data_temp); //--- for(int i=0; i<size_of_series; i++) { m_series[s].data_temp[i]+=m_offset_series.GetValue(); //--- switch(Formula) { case FORMULA_1 : m_series[s].data[i]=::sin(m_series[s].data_temp[i])-::cos(m_series[s].data_temp[i]); break; case FORMULA_2 : m_series[s].data[i]=::sin(m_series[s].data_temp[i]-::cos(m_series[s].data_temp[i])); break; case FORMULA_3 : m_series[s].data[i]=::sin(m_series[s].data_temp[i]*10)-::cos(m_series[s].data_temp[i]); break; } } } }
系列の計算されたデータが配列に移動された後はそれらは (1) CProgram::AddSeries()メソッドでチャートに追加するか、すでに追加されている場合は (2) CProgram::UpdateSeries()メソッドで更新します。
class CProgram : public CWndEvents { private: //--- チャートへの系列の追加 void AddSeries(void); //--- チャートでの系列の更新 void UpdateSeries(void); }; //+------------------------------------------------------------------+ //| 系列を計算してダイアグラムで設定する | //+------------------------------------------------------------------+ void CProgram::AddSeries(void) { int total=(int)m_series_total.ButtonText(); for(int s=0; s<total; s++) m_line_chart.SeriesAdd(m_series[s].data,m_series_name[s],m_series_color[s]); } //+------------------------------------------------------------------+ //| 系列を計算してダイアグラムで設定する | //+------------------------------------------------------------------+ void CProgram::UpdateSeries(void) { int total=(int)m_series_total.ButtonText(); for(int s=0; s<total; s++) m_line_chart.SeriesUpdate(s,m_series[s].data,m_series_name[s],m_series_color[s]); }
折れ線グラフの作成後は(1) 系列の配列サイズが設定され (2) 補助配列の初期化が行われます。その後系列が (3) 計算されて (4) チャートに追加されます。
//+------------------------------------------------------------------+ //| 折れ線グラフの作成 | //+------------------------------------------------------------------+ bool CProgram::CreateLineChart(void) { //--- ウィンドウポインタを格納する m_line_chart.WindowPointer(m_window1); //--- 座標 int x=m_window1.X()+LINECHART1_GAP_X; int y=m_window1.Y()+LINECHART1_GAP_Y; //--- 作成前にプロパティを設定する m_line_chart.XSize(630); m_line_chart.YSize(280); m_line_chart.BorderColor(clrSilver); m_line_chart.VScaleParams(2,-2,4); m_line_chart.MaxData(int(m_series_total.ButtonText())); //--- コントロールを作成する if(!m_line_chart.CreateLineGraph(m_chart_id,m_subwin,x,y)) return(false); //--- (1) 配列サイズを設定し (2) 初期化する ResizeDataArrays(); InitArrays(); //--- (1) 計算し (2) チャートに系列を追加する CalculateSeries(); AddSeries(); //--- ベースでのコントロールにポインタを追加する CWndContainer::AddToElementsArray(0,m_line_chart); return(true); }
同じ一連のアクションは頻繁に繰り返される必要がありますがこれは折れ線グラフのコントロールと相互接続する際に一連の更新が行われる時だけです。よって、4つのメソッドを呼ぶ代わりに1つですむようにCProgram::RecalculatingSeries() 補助メソッドを書きます。
class CProgram : public CWndEvents { private: //--- チャートの系列の再計算 void RecalculatingSeries(void); }; //+------------------------------------------------------------------+ //| チャートの系列の再計算 | //+------------------------------------------------------------------+ void CProgram::RecalculatingSeries(void) { //--- (1) 配列サイズを設定し (2) 初期化する ResizeDataArrays(); InitArrays(); //--- 系列を(1) 計算して (2) 更新する CalculateSeries(); UpdateSeries(); }
開発の現段階では、チャート上のアプリケーションをダウンロードすることによって以下の結果が得られます。
図4 折れ線グラフコントロールの検証
チェックボックスパラメータのMax. limit sizeが有効な場合はCProgram::AutoResizeLineChartSeries() メソッドの系列の配列の自動サイズ調整が起動します。このアルゴリズムはこのセクションの冒頭ですでに十分に説明されたので、このメソッドのコードの研究には詳細なコメントで十分です(以下のコードを参照)。
class CProgram : public CWndEvents { private: //--- チャート系列の自動サイズ調整 void AutoResizeLineChartSeries(void); }; //+------------------------------------------------------------------+ //| チャート系列の自動サイズ調整 | //+------------------------------------------------------------------+ void CProgram::AutoResizeLineChartSeries(void) { //--- タイマーでの系列の配列の増加が無効になっている場合は終了する if(!m_max_limit_size.CheckButtonState()) return; //--- 配列のサイズを変更する方向を示す static bool resize_direction=false; //--- 配列の最小サイズが到達した場合 if((int)m_series_size.GetValue()<=m_min_limit_size.GetValue()) { //--- 配列の増加方向に切り替える resize_direction=false; //--- X値の変更が必要な場合 if(m_increment_ratio.CheckButtonState()) { //--- 増加率の方向を示す static bool increment_ratio_direction=true; //--- カウンタが増加方向の場合 if(increment_ratio_direction) { //--- 最大限に達した場合はカウンタの方向を反対方向を変更する if(m_increment_ratio.GetValue()>=m_increment_ratio.MaxValue()-1) increment_ratio_direction=false; } //--- カウンタが減少方向の場合 else { //--- 最小限に達した場合はカウンタの方向を反対方向を変更する if(m_increment_ratio.GetValue()<=m_increment_ratio.MinValue()+1) increment_ratio_direction=true; } //--- 「Increment ratio」パラメータの現在値を取得して示された方向で変える int increase_value=(int)m_increment_ratio.GetValue(); m_increment_ratio.ChangeValue((increment_ratio_direction)?++increase_value : --increase_value); } } //--- 最大値が到達したら配列サイズの減少に切り替える if((int)m_series_size.GetValue()>=m_max_limit_size.GetValue()) resize_direction=true; //--- プログレスバーが有効な場合はプロセスを表示する if(m_progress_bar.IsVisible()) { if(!resize_direction) m_progress_bar.Update((int)m_series_size.GetValue(),(int)m_max_limit_size.GetValue()); else m_progress_bar.Update(int(m_max_limit_size.GetValue()-m_series_size.GetValue()),(int)m_max_limit_size.GetValue()); } //--- 方向に応じて配列サイズを変える int size_of_series=(int)m_series_size.GetValue(); m_series_size.ChangeValue((!resize_direction)?++size_of_series : --size_of_series); //--- 配列の初期サイズを設定する ResizeDataArrays(); }
前述したように、グラフのアニメーションはタイマーで実行されます。必要なアクションはすべてCProgram::UpdateLineChartByTimer()メソッドに位置します。(1) フォームが最小化されるまたは (2) タイマーによる系列更新が無効化されている場合には、プログラムは即時メソッドを終了します。さらに、ここでのあと1つの障害は編集ボックスのdelayです。すべてのチェックが完了した場合、有効モードのために必要な計算がさらに実行され、折れ線グラフの系列が更新されます。
class CProgram : public CWndEvents { private: //--- タイマーによる折れ線グラフの更新 void UpdateLineChartByTimer(void); }; //+------------------------------------------------------------------+ //| タイマーによる更新 | //+------------------------------------------------------------------+ void CProgram::UpdateLineChartByTimer(void) { //--- フォームが最小化されているかまたはシフトの過程の場合は終了する if(m_window1.IsMinimized()) return; //--- アニメーションが無効な場合は終了する if(!m_max_limit_size.CheckButtonState() && !m_run_speed.CheckButtonState()) return; //--- 遅れ static int count=0; if(count<m_delay_ms.GetValue()) { count+=TIMER_STEP_MSC; return; } count=0; //--- 「Running series(実行中の系列)」オプションが無効な場合は、系列の初めの値をシフトする ShiftLineChartSeries(); //--- タイマーによる系列の配列サイズ管理が有効な場合 AutoResizeLineChartSeries(); //--- 配列を初期化する InitArrays(); //--- 系列を(1) 計算して (2) 更新する CalculateSeries(); UpdateSeries(); }
開発されたアプリケーションのCProgram::OnEvent() イベントハンドラを簡単にみてみます. 折れ線グラフ上で瞬間的に視覚的な変更を行うには、下記のコントロールが使用されます。
- Number of series(系列の数)パラメータ(コンボボックス)。折れ線グラフの系列の数はこのコントロールに新しい値を選択するたびに変更されます。このイベントを処理するためのコードブロックは、以下のリストに示されています。
... //--- コンボボックス内の項目を選択するイベント if(id==CHARTEVENT_CUSTOM+ON_CLICK_COMBOBOX_ITEM) { //--- 系列の新しい合計を取得する m_line_chart.MaxData((int)m_series_total.ButtonText()); //--- (1) 配列サイズを設定し (2) 初期化する ResizeDataArrays(); InitArrays(); //--- 系列を(1) 計算 (2) チャートに追加 (3) 更新する CalculateSeries(); AddSeries(); UpdateSeries(); return; } ...
例として、コンボボックスではデフォルトで6つの系列が表示されます(6値)。これを3に変えます。結果は以下のスクリーンショットに見られます。
図5 折れ線グラフで系列の合計を変更するテスト
- Max parameters limit size(パラメータの最大数)(編集ボックスとチェックボックス) とSize of series(系列サイズ)(編集ボックス)。これらのコントロールがクリックされるとON_CLICK_LABEL識別子を持つイベントが生成されます。Size of series(系列サイズ)コントロールがクリックされると、編集ボックスでの値が最小値にリセットされます。Max control limit size(コントロールの最大サイズ)をクリックするとチェックボックスの状態が反転します。自動的に折れ線グラフ上の系列の自動サイズ調整モードが有効にされたときに実証されているプログレスバーが表示されるかどうかはチェックボックスの状態によって異なります。
... //--- コントロールのテキストラベルのクリックイベント if(id==CHARTEVENT_CUSTOM+ON_CLICK_LABEL) { //--- このメッセージが「Size of series(系列サイズ)」コントロールからの場合 if(sparam==m_series_size.LabelText()) { //--- チャートの系列の再計算 RecalculatingSeries(); return; } //--- このメッセージが「Max. Limit Size(最大値)」 コントロールからの場合 if(sparam==m_max_limit_size.LabelText()) { //--- 「Max. Limit Size(最大値)」のチェックボックスの状態によってプログレスバーを表示/非表示にする if(m_max_limit_size.CheckButtonState()) m_progress_bar.Show(); else m_progress_bar.Hide(); //--- return; } } ...
以下のスクリーンショットは、これがプロセスでどのように見えるかの例を示します。
図6。系列の自動サイズ調整モードでの折れ線グラフの検証
- Increment ratio(増加率)、Offset series(系列オフセット)およびSize of series(系列サイズ)の編集ボックスに値を入力すると系列の再計算のためにCProgram::RecalculatingSeries()メソッドが呼び出されます(下記のコードを参照)。
... //--- 編集ボックスでの値の入力イベント if(id==CHARTEVENT_CUSTOM+ON_END_EDIT) { //--- このメッセージが「Increment ratio」、「Offset series」、「Size of series」コントロールからの場合 if(sparam==m_increment_ratio.LabelText() || sparam==m_offset_series.LabelText() || sparam==m_series_size.LabelText()) { //--- チャートの系列の再計算 RecalculatingSeries(); return; } return; } //--- 編集ボックスのスイッチボタンのクリックイベント if(id==CHARTEVENT_CUSTOM+ON_CLICK_INC || id==CHARTEVENT_CUSTOM+ON_CLICK_DEC) { //--- このメッセージが「Increment ratio」、「Offset series」、「Size of series」コントロールからの場合 if(sparam==m_increment_ratio.LabelText() || sparam==m_offset_series.LabelText() || sparam==m_series_size.LabelText()) { //--- チャートの系列の再計算 RecalculatingSeries(); return; } return; } ...
下のスクリーンショットはあと1つの例を示します。ご自分のコピーで同じパラメータを設定して、それがアニメーションモードでどのように見えるかをご確認ください。
図7 「running series(実行中の系列)」モードの検証
標準ライブラリのクラスのコピーに変更が加えられた後、複数要素配列は折れ線グラフの系列の領域に正しく配置されます。以下のスクリーンショットは系列サイズがコントロールの1000分の1に等しいときの例を示します(Size of series(系列サイズ)パラメータを参照)。
図8 データ数の多い系列の検証
検証のためのアプリケーションの用意が完了です。本稿末尾でこのエキスパートアドバイザーのファイルをダウンロードして検証することができます。
おわりに
本稿では、プログレスバーや折れ線グラフインターフェースコントロールを作成するために使用されるコードクラスを提示しました。
グラフィカルインタフェースを作成するためのライブラリーの概略は現在以下の通りに見えます。いくつかの断片は単に一時的な解決策であり、いくつかの変更はライブラリの開発とともに紹介されます。
図9 開発の現段階でのライブラリの構造
これでMetaTraderのグラフィカルインタフェースを作成するためのEasy And Fast(簡単かつ手早い) ライブラリの開発に関するシリーズが完了します。次の記事からはこのライブラリでの作業に焦点が当てられます。そこでは、様々な例、追加や更新が提供されます。ご希望の場合は、このプロジェクトの開発への参加も可能です。結果に満足なされた場合は、プロジェクトでライブラリを検証し、見つかったエラーを報告し質問をなさってください。
以下は、ダウンロード後に検証可能な資料のすべてです。これらのファイルに含まれている資料の使用についてご質問がある場合は、以下のリストにある記事のいずれかでライブラリの開発の詳細をご参照になるか、本稿へのコメント欄でご質問ください。
第九部の記事(チャプター)のリストは下記の通りです。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/2580





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