グラフィカルインタフェースを備えたユニバーサルチャンネル
コンテンツ
- イントロダクション
- 中心線の種類
- ボーダーの種類
- 幅を計算し、チャネルを描画するためのクラス
- ユニバーサルチャネルインジケータの作成
- グラフィカルインターフェイスクラスの作成
- 中心線コントロールのクラス
- 幅計算コントロールのクラス
- フォームクラス
- インジケータとグラフィカルインタフェースの接続
- 結論
- 添付
イントロダクション
前の記事では、グラフィカルインターフェイスを使用したユニバーサルオシレーターの作成について説明しました。 その記事では、かなり簡素化し、チャートの分析を高速化する非常に便利なインジケータを作成しました。 オシレーターに加えて、他の種類のテクニカルインジケータがあり、それらはオシレーターとして興味深いものになるかもしれません。 トレンド、ボラティリティ、ボリュームだけでなく、様々なカテゴリに分けることができるインジケーターがあります。 この記事では、ユニバーサルチャネルインジケータの作成を検討します。
普遍的なオシレーターについての前の記事は非常に複雑であり、ベテランのプログラマー向けに意図されていました。 この記事のトピックはユニバーサルオシレーターの作成に近いので、ここでは一般的な問題を繰り返すことはありません。 ユニバーサルオシレーターに基づいてユニバーサルチャンネルを作成します。 したがって、初心者のプログラマも、グラフィカルインターフェイスを持つ普遍的なインジケーターの作成のすべてを理解することなく、変更を加えることによって、ユニバーサルインジケータを作成することができます。
インジケーターの類似性によらず、根本的な違いがあるでしょう。 すべてのチャネルインジケータは、上中下の3ラインとして表示されます。 移動平均インジケーターは主にチャネルに使用されますが、中央の線の描画原理は移動平均に似ています。 上下の線は中心線から等しい距離に位置します。 この距離は、標準偏差値 ( ボリンジャーバンドバンド)、またはatr値 (ケルトナーチャネル) を使用して、価格の割合 (エンベロープインジケータ) としてポイント単位で決定できます。 したがって、チャネルインジケータは、2つの独立したブロックを使用して構築されます。
- 中心線の計算ブロック
- チャンネルの幅を定義するブロック (または図面チャネルの境界線)
ドンチャン チャンネル (価格チャンネル) など、異なるタイプのチャンネルがあります。 通常、ボーダーライン (価格帯) の作成から始まり、その後、中心線の値が(その範囲の真ん中に) 計算されます。 しかし、このチャネルは、上記のスキームによって構築することができます。すなわち、最初に価格の範囲の真ん中として定義し、そして値幅の半分に等しいチャネルの境界線を描くというスキームです。 もちろん、通常のチャネルよりも多くの計算が必要になります。 しかし、この記事の主な目的は、ユニバーサルインジケータを作成することなので、このアプローチは中心線とボーダーの可能な組み合わせの数を増やし、例外を入れることができます。 例えば、ボリンジャーバンドなどのような標準偏差の境界線と、価格チャネルで使用される中心線を持つインジケーターを作成することができます。
中心線の種類
中心線にはさまざまな移動平均が使用されます。 その型とパラメータの数を定義してみましょう。 インジケーターで使用される中心線のすべてのバリアントを表1に示します。
表 1. 中心線の種類
Standard function |
Name | Parameters |
---|---|---|
iAMA | アダプティブ移動平均 | 1. nt ama_period — ama 期間 2. nt fast_ma_period-短期移動平均期間 3. nt slow_ma_period —長期移動平均期間 4. nt ama_shift —インジケーターの水平方向のシフト 5. ENUM_APPLIED_PRICE APPLIED_PRICE-ハンドルハンドルの価格タイプ |
iDEMA | 2重指数移動平均 | 1. nt ma_period-平均化期間 2. nt ma_shift —インジケーターの水平方向のシフト 3. ENUM_APPLIED_PRICE APPLIED_PRICE-価格タイプ |
iFrAMA | フラクタル適応移動平均 | 1. nt ma_period-平均化期間 2. nt ma_shift —インジケーターの水平方向のシフト 3. ENUM_APPLIED_PRICE APPLIED_PRICE-価格タイプ |
iMA | 移動平均 | 1. nt ma_period-平均化期間 2. nt ma_shift —インジケーターの水平方向のシフト 3. ENUM_MA_METHOD MA_METHOD-スムージングタイプ 4. ENUM_APPLIED_PRICE APPLIED_PRICE-価格タイプ |
iTEMA | 3重指数移動平均 | 1. nt ma_period-平均化期間 2. nt ma_shift —インジケーターの水平方向のシフト 3. ENUM_APPLIED_PRICE APPLIED_PRICE-価格タイプ |
iVIDyA | 可変インデックスの動的平均 | 1. nt cmo_period-シャンデリア勢いの期間 2. nt ema_period-スムージングファクター期間 3. nt ma_shift —インジケーターの水平方向のシフト 4. ENUM_APPLIED_PRICE APPLIED_PRICE-価格タイプ |
- | 価格チャネルの中心線 | 1. int period |
表1の「パラメタ」欄の解析に基づき、必要最低限のパラメータセットを得ました (表 2)。
表 2. チャネルの中心線の計算のパラメータのセット
Type | Name |
---|---|
int | period1 |
int | period2 |
int | period3 |
int | shift |
ENUM_MA_METHOD | ma_method |
ENUM_APPLIED_PRICE | price |
ボーダーの種類
チャネルの境界計算バリアントを決定しましょう (表 3)。
表 3. チャネル幅の計算バリアント
Standard function |
Name | Parameters |
---|---|---|
iATR | トゥルーレンジの平均 | 1. nt ma_period-平均化期間 |
iStdDev | 標準偏差 | 1. nt ma_period-平均化期間 2. nt ma_shift —インジケーターの水平方向のシフト 3. ENUM_MA_METHOD-スムージングタイプ 4. ENUM_APPLIED_PRICE APPLIED_PRICE-価格タイプ |
- | in points | int width—ポイントの幅 |
- | パーセンテージ (エンベロープのライン) | double width-価格のパーセンテージとしての幅 |
- | 価格チャンネル | double width-価格チャネルの実際の幅に対する尺度の比率 |
表3の「パラメータ」欄に基づき、必要なパラメータセットを取得しました(表 4)。
表4. チャネル幅を計算するための普遍的なパラメータセット
Type | Name |
---|---|
int | period |
int | shift |
ENUM_MA_METHOD | ma_method |
ENUM_APPLIED_PRICE | price |
double | width |
ポイント単位で計算に int 変数が必要ですが、代わりに double 変数を使用できるため、表4に含まれていません。 これにより、[プロパティ] ウィンドウの変数の総数が減ります。
すべての境界線の計算パラメータは、インジケータのプロパティウィンドウに "w_" プレフィックスと共に表示されます。
中心線のクラス
中心線の基本クラスは、基本的な原理とメソッドのセットに関して、「ユニバーサルオシレーター gui 」で説明した CUniOsc クラスに似ています。 したがって、若干変更されます。
MQL5/include フォルダで、UniChannelフォルダを作成し、 URCUniOsc.mqh ファイル (インクルード/UniOsc) からコピーして、URCUniChannel.mqh に名前を変えます。 基本クラス (COscUni) 、子クラス Calculate1 (その完全な名前は COscUni_Calculate1) とその子クラス COscUni_ATRをファイルに残します。 他のクラスを削除する必要があります。
クラスの名前を変更しましょう。: "CChannelUni" に "COscUni" フラグメントを置き換える。 置き換えるために、エディタ関数 (メインメニュー-[編集]-[検索と置換]-置換) を使用します。 しかし、"すべてを置き換える" ボタンは使用しないでください。 インスタンスを1つずつ置き換えて、すべての置換が正しいことを確認します。
中心線クラスは常に1つの実線を描画するため、基本クラスのメソッドの多くは必要ありません。 不要なメソッドを削除した後、次の基本クラスが残されます。
class CChannelUniWidth{ protected: int m_handle; // indicator handle string m_name; // indicator name string m_label1; // name of buffer 1 string m_help; // a help on indicator parameters double m_width; // channel width public: // constructor void CChannelUniWidth(){ m_handle=INVALID_HANDLE; } // destructor void ~CChannelUniWidth(){ if(m_handle!=INVALID_HANDLE){ IndicatorRelease(m_handle); } } // the main method called from the OnCalculate() function of the indicator virtual int Calculate( const int rates_total, const int prev_calculated, double & bufferCentral[], double & bufferUpper[], double & bufferLower[], ){ return(rates_total); } // getting the handle of the loaded indicator int Handle(){ return(m_handle); } // handle checking method, which allows to check if the indicator has been loaded successfully bool CheckHandle(){ return(m_handle!=INVALID_HANDLE); } // getting the indicator name string Name(){ return(m_name); } // getting the label text for the buffers string Label1(){ return(m_label1); } // getting the hint on parameters string Help(){ return(m_help); } };
2番目のバッファに関連するすべては、calculate クラスから削除できます。 その後、1つだけ計算メソッドが残されます:
class CChannelUni_Calculate1:public CChannelUni{ public: // the main method called from the OnCalculate() function of the indicator // The first two parameters are similar to the first two parameters // of the OnCalculate() function of the indicator // The third parameter is the indicator buffer for the central line int Calculate( const int rates_total, const int prev_calculated, double & buffer0[] ){ // determining the number of copied elements int cnt; if(prev_calculated==0){ cnt=rates_total; } else{ cnt=rates_total-prev_calculated+1; } // copying data to the indicator buffer if(CopyBuffer(m_handle,0,0,cnt,buffer0)<=0){ return(0); } return(rates_total); } };
iMAインジケータを使用して子クラスを記述します。 CChannelUni_ATR クラスを CChannelUni_MA に変更する必要があります。 呼び出されたインジケータを交換し、必要ない部品を削除してみましょう。 その結果、次のクラスを取得します。
class CChannelUni_MA:public CChannelUni_Calculate1{ public: // constructor // the first two parameters are the same for all child classes // then parameters of the loaded indicator void CChannelUni_MA( bool use_default, bool keep_previous, int & ma_period, int & ma_shift, long & ma_method, long & ma_price){ if(use_default){ // use of default values is selected if(keep_previous){ // no modification of previously used parameters if(ma_period==-1)ma_period=14; if(ma_shift==-1)ma_shift=0; if(ma_method==-1)ma_method=MODE_SMA; if(ma_price==-1)ma_price=PRICE_CLOSE; } else{ ma_period=14; ma_shift=0; ma_method=MODE_SMA; ma_price=PRICE_CLOSE; } } // loading the indicator m_handle=iMA(Symbol(),Period(),ma_period,ma_shift,(ENUM_MA_METHOD)ma_method,(ENUM_APPLIED_PRICE)ma_price); // forming a line with the indicator name m_name=StringFormat( "iMA(%i,%i,%s,%s)", ma_period, ma_shift, EnumToString((ENUM_MA_METHOD)ma_method), EnumToString((ENUM_APPLIED_PRICE)ma_price) ); // String for the buffer name m_label1=m_name; // hint on parameters m_help=StringFormat( "ma_period - c_Period1(%i), "+ "ma_shift - c_Shift(%i), "+ "ma_method - c_Method(%s)"+ "ma_price - c_Price(%s)", ma_period, ma_shift, EnumToString((ENUM_MA_METHOD)ma_method), EnumToString((ENUM_APPLIED_PRICE)ma_price) ); } };
文字列が変数 m_name と mlabel1 で形成されるメソッドを詳しく見てみましょう。 サブウィンドウの左上隅にインジケータ名 (m_name 変数) が表示されます (サブウインドウ)。 チャンネルは価格チャートに表示されますが, その名前は表示されません。したがって、 m_label 変数に割り当てられている同じ m_name 変数に, すべてのパラメータがポップアップヘルプで表示されたときに中央のチャネル上にマウスを置くようにします。
他のすべての標準インジケータのクラスは、iMAと同様に作成されます。 例外は、価格チャネルです。 価格チャネルは、標準のターミナルインジケータのセットに含まれていないため、計算する必要があります。 2つの方法が可能です。
- 計算型の子クラスの作成とその計算です。
- 追加のインジケーターを作成し、iCustom 関数を使用して呼び出します。
下の添付ファイルには、他のすべてのインジケータと iPriceChannel インジケータの子クラスを持つ URCUniChannel.mqh があります。 iPriceChannel インジケータの中心線のデータは、バッファ0です。 必要なデータがゼロ以外のバッファに配置されている場合は、別の計算サブクラスを作成するか、基本クラスのバッファインデックスの変数を作成し、そのサブクラスのコンストラクターで目的の値を代入する必要があります。
幅を計算し、チャネルを描画するためのクラス
再び基本クラスの基礎として CUniChannel を使用してみましょう。 中心線の値と、メソッドで計算された値で満たされるチャネルボーダーの2つのバッファのインジケーターバッファが、calculate クラスメソッドに渡されます。 CUniChannel とは対照的に、ここでは、各ボーダーの計算オプションの子クラスを別々に計算します。 サブクラスにはインジケータが読み込まれ、インジケータとバッファの名前がその中に形成されます。 また、基本クラスを若干変更する必要があります。チャネルの幅の変数を追加するため、変数の値は、子クラスのコンストラクターを通じて設定されます。
URCUniChannelWidth.mqh として URCUniChannel.mqh filde を保存し、変更してみましょう。 まず、すべての子クラスを削除し、基本クラスのみを残して計算します。 CChannelUni の名前を CChannelUniWidth に変更 (コンストラクター、デストラクター、および子クラスの親名を忘れないでください)する必要もあります。 結果のファイルは次のとおりです。
class CChannelUniWidth{ protected: int m_handle; // indicator handle string m_name; // indicator name string m_label1; // name of buffer 1 string m_help; // a hint on indicator parameters double m_width; // channel width public: // constructor void CChannelUniWidth(){ m_handle=INVALID_HANDLE; } // destructor void ~CChannelUniWidth(){ if(m_handle!=INVALID_HANDLE){ IndicatorRelease(m_handle); } } // the main method called from the OnCalculate() function of the indicator virtual int Calculate( const int rates_total, const int prev_calculated, double & bufferCentral[], double & bufferUpper[], double & bufferLower[], ){ return(rates_total); } // getting the handle of the loaded indicator int Handle(){ return(m_handle); } // handle checking method, which allows to check if the indicator has been loaded successfully bool CheckHandle(){ return(m_handle!=INVALID_HANDLE); } // getting the indicator name string Name(){ return(m_name); } // getting the label text for the buffers string Label1(){ return(m_label1); } // getting the hint on parameters string Help(){ return(m_help); } };
CChannelUni_Calculate クラスの名前を CChannelUni_Calculate_ATR に変更し、コンストラクタを追加してみましょう。 コンストラクタは、ユニバーサルオシレーターの COscUni_ATR クラスから取得できますが、 幅パラメータを変更する必要があります。 他に何を変更する必要があるでしょうか。インジケータとバッファの名前の生成を追加する必要があります。 そして最後に、ATR に基づいてボーダーを計算します。
class CChannelUni_Calculate_ATR:public CChannelUniWidth{ public: // constructor // the first two parameters are standard for all child classes // followed by parameters of the loaded indicator // the last parameter is the channel width void CChannelUni_Calculate_ATR(bool use_default, bool keep_previous, int & ma_period, double & ch_width){ if(use_default){ // use of default values is selected if(keep_previous){ // no modification of previously used parameters if(ma_period==-1)ma_period=14; if(ch_width==-1)ch_width=2; } else{ ma_period=14; ch_width=2; } } // saving width parameters for use in the calculation metho m_width=ch_width; // loading the indicator m_handle=iATR(Symbol(),Period(),ma_period); // forming a line with the indicator name m_name=StringFormat("ATR(%i)",ma_period); // string with the names of the buffers m_label1=m_name; // hint on parameters m_help=StringFormat("ma_period - Period1(%i)",ma_period); // a hint } // the main method called from the OnCalculate() function of the indicator // the first two parameters are similar to the first two parameters // of OnCalculate() function // then indicator buffers are passed int Calculate( const int rates_total, const int prev_calculated, double & bufferCentral[], double & bufferUpper[], double & bufferLower[], ){ // defining the beginning of calculation int start; if(prev_calculated==0){ start=0; } else{ start=prev_calculated-1; } // the main loop of calculation and buffer filling for(int i=start;i<rates_total;i++){ // getting indicator data for the calculated bar double tmp[1]; if(CopyBuffer(m_handle,0,rates_total-i-1,1,tmp)<=0){ return(0); } // multiplying by the width parameter tmp[0]*=m_width; // calculating the values of the upper and lower borders bufferUpper[i]=bufferCentral[i]+tmp[0]; bufferLower[i]=bufferCentral[i]-tmp[0]; } return(rates_total); } };
1つの足のATRインジケータの値は、メインループ内にコピーされることに注意してください、 このバリアントは、系列をバッファにコピーするよりもはるかに低速です。 しかし、このアプローチでは、1つのインジケーターバッファを保存しますが、チャートにインジケータを裁量でアタッチするときにのみ表示されます。 しかし、2番目の遅延は、ユーザーにとって不可欠ではありません。 ストラテジーテスタでは、テストの開始時にチャート上のわずかな足が利用可能であるため、各足のデータをコピーしても時間が失われることはありません。
チャネル幅の計算に、幅がポイントまたはエンベロープチャネルで設定されている場合などは、追加のインジケータは必要ありません。 この場合、基本クラスの m_handle 変数に0を代入します (INVALID_HANDLE 値とは異なります)。
下の添付ファイルに、他のチャネル計算オプションの子クラスを持つ URCUniChannelWidth.mqh があります。
ユニバーサルチャネルインジケータの作成
上記のクラスを用意したので、ユニバーサルチャネルインジケータを作成することもできますが、グラフィカルインターフェイスはまだありません。
エディタで新しい iUniChannel カスタムインジケータを作成しましょう。 MQL5 ウィザードでインジケーターを作成するときは、次の関数を選択します。 OnCalculate (...,始値、高値、安値、終値), OnTimer, OnChartEvent, ラインタイプの3つのバッファを作成します。
中心線とチャネルの種類を選択するには、2つの列挙型を作成する必要があります。 列挙体は URUniChannelDefines.mqh ファイルに配置されます。 表1および3に従って列挙を作成します:
// enumeration of central line types enum ECType{ UniCh_C_AMA, UniCh_C_DEMA, UniCh_C_FrAMA, UniCh_C_MA, UniCh_C_TEMA, UniCh_C_VIDyA, UniCh_C_PrCh }; // enumeration of border types enum EWType{ UniCh_W_ATR, UniCh_W_StdDev, UniCh_W_Points, UniCh_W_Percents, UniCh_W_PrCh };
中心線の種類の列挙体は ECType と呼ばれ、チャネル幅の種類の列挙は EWType です。 列挙体と、以前に作成された2つのファイルとクラスを持つファイルをインジケーターに接続します。
#include <UniChannel/UniChannelDefines.mqh> #include <UniChannel/CUniChannel.mqh> #include <UniChannel/CUniChannelWidth.mqh>
次に、2つの外部変数を宣言して、中心線の種類とチャネル幅を選択し、表2および表4に従ってパラメータの変数を指定します。
// central line parameters input ECType CentralType = UniCh_C_MA; input int c_Period1 = 5; input int c_Period2 = 10; input int c_Period3 = 15; input int c_Shift = 0; input ENUM_MA_METHOD c_Method = MODE_SMA; input ENUM_APPLIED_PRICE c_Price = PRICE_CLOSE; // border parameters input EWType WidthType = UniCh_W_StdDev; input int w_Period = 20; input int w_Shift = 0; input ENUM_MA_METHOD w_Method = MODE_SMA; input ENUM_APPLIED_PRICE w_Price = PRICE_CLOSE; input double w_Width = 2.0;
2つの変数を宣言し、後で GUI を使用してインジケータのプロパティウィンドウに表示されます:
bool UseDefault = false; bool KeepPrev = false;
変数の目的は、ユニバーサルオシレーターについての記事で詳しく説明されています。UseDefault 変数は、新しく選択された各インジケータがデフォルト設定で読み込まれるモードを有効にし、KeepPrev 変数がインジケータを切り替えるときにパラメータを保存するモードを有効にします。 GUIを使用しないインジケーターバージョンでは、インジケータは [プロパティ] ウィンドウのパラメータで読み込まれ、UseDefault 値は false になります。 KeepPrev も false に設定されているため、インジケータスイッチはありません。
インジケーターの初期化中にパラメータを準備する必要があります。 ユニバーサルオシレーターのように、別の関数 PrepareParameters () でパラメータを準備しますが、最初にすべての外部変数のコピーを作成します:
ECType _CentralType; int _ma_Period1; int _ma_Period2; int _ma_Period3; int _ma_Shift; long _ma_Method; long _ma_Price; EWType _WidthType; int _w_Period; int _w_Shift; long _w_Method; long _w_Price; double _w_Width;
次に、パラメータの準備関数を記述します。
void PrepareParameters(){ _CentralType=CentralType; _WidthType=WidthType; if(UseDefault && KeepPrev){ _c_Period1=-1; _c_Period2=-1; _c_Period3=-1; _c_Shift=0; _c_Method=-1; _c_Price=-1; _w_Period=-1; _w_Shift=0; _w_Method=-1; _w_Price=-1; _w_Width=-1; } else{ _c_Period1=c_Period1; _c_Period2=c_Period2; _c_Period3=c_Period3; _c_Shift=c_Shift; _c_Method=c_Method; _c_Price=c_Price; _w_Period=w_Period; _w_Shift=w_Shift; _w_Method=w_Method; _w_Price=w_Price; _w_Width=w_Width; } }
UseDefault & & KeepPrev 条件が満たされると、すべての変数が-1 に設定され、ユーザーインターフェイス (インジケータのプロパティウィンドウまたは gui) から設定されるので、shift 変数に0が割り当てられます。
パラメータを準備した後、中心線とチャネルを計算するオブジェクトを作成できます。 ユニバーサルオシレーターでは、LoadOscillator () 関数をその目的で使用します。 ここでは、LoadCentral () と LoadWidth () の2つの関数がありますが、最初にポインタを宣言する必要があります。
CChannelUni * central; CChannelUniWidth * width;
すべてのインジケータがシフトすることは共通ですが、水平方向のシフトのパラメータを持つものともたないものがあります。 したがって、付加的な変数 shift0 を0の値で宣言し、クラスコンストラクタで渡します。 このシフトは、インジケーターバッファをシフトすることによって描画されます。
LoadCentral () 関数:
void LoadCentral(){ switch(_CentralType){ // an appropriate class is created depending on the selected type case UniCh_C_AMA: central=new CChannelUni_AMA( UseDefault, KeepPrev, _c_Period1, _c_Period2, _c_Period3, shift0, _c_Price); break; case UniCh_C_DEMA: central=new CChannelUni_DEMA( UseDefault, KeepPrev, _c_Period1, shift0, _c_Price); break; case UniCh_C_FrAMA: central=new CChannelUni_FrAMA(UseDefault, KeepPrev, _c_Period1, shift0, _c_Price); break; case UniCh_C_MA: central=new CChannelUni_MA( UseDefault, KeepPrev, _c_Period1, shift0, _c_Method, _c_Price); break; case UniCh_C_TEMA: central=new CChannelUni_TEMA( UseDefault, KeepPrev, _c_Period1, shift0, _c_Price); break; case UniCh_C_VIDyA: central=new CChannelUni_VIDyA(UseDefault, KeepPrev, _c_Period1, _c_Period2, shift0, _c_Price); break; case UniCh_C_PrCh: central=new CChannelUni_PriceChannel( UseDefault, KeepPrev, _c_Period1); break; } }
チャネル幅の計算オプション (CChannelUni_Calculate_InPoints クラス) の1つがポイントで測定されたパラメータを含み、クラスはシンボルクオートの小数点以下の桁数に従ってパラメータ値を調整します。 関数を操作するには、オブジェクトを作成するときに、パラメータをクラスコンストラクタに渡す必要があります。 2桁4 桁のクオートでは、乗数は1に等しくなり、3桁5桁のクオートでは10になります。 外部パラメータで、bool 型の Auto5Digits 変数を宣言します。
Auto5Digits が true の場合、false-値がそのまま使用される場合には修正されます。 Auto5Digits の下で、変数をもう1つ宣言します。
OnInit () 関数の冒頭で、mult の値を計算します。
if(Auto5Digits && (Digits()==3 || Digits()==5)){ mult=10; // parameters in points will be multiplied by 10 } else{ mult=1; // parameters in points will not be corrected }
LoadWidth () 関数:
void LoadWidth(){ switch(_WidthType){ // an appropriate class is created depending on the selected type case UniCh_W_ATR: width=new CChannelUni_Calculate_ATR(UseDefault,KeepPrev,_w_Period,_w_Width); break; case UniCh_W_StdDev: width=new CChannelUni_Calculate_StdDev(UseDefault,KeepPrev,_w_Period,shift0,_w_Method,_w_Price,_w_Width); break; case UniCh_W_Points: width=new CChannelUni_Calculate_InPoints(UseDefault,KeepPrev,_w_Width,mult); break; case UniCh_W_Percents: width=new CChannelUni_Calculate_Envelopes(UseDefault,KeepPrev,_w_Width); break; case UniCh_W_PrCh: width=new CChannelUni_Calculate_PriceChannel(UseDefault,KeepPrev,_w_Period,_w_Width); break; } }
各オブジェクト (中心線と幅) を作成した後、正常に作成されたかどうかを確認する必要があります。 オブジェクトが作成された場合は、インジケータのショートネームを設定し、print () 関数を使用してパラメータのヘルプ情報を表示します。
Print("Central line parameters matching:",central.Help()); Print("Width parameters matching:",width.Help());
バッファのラベルとシフトは、setstyles () 関数を使用して設定されます。
void SetStyles(){ // buffer names PlotIndexSetString(0,PLOT_LABEL,"Central: "+central.Label1()); PlotIndexSetString(1,PLOT_LABEL,"Upper: "+width.Label1()); PlotIndexSetString(2,PLOT_LABEL,"Lower: "+width.Label1()); // shift of buffers PlotIndexSetInteger(0,PLOT_SHIFT,_c_Shift); PlotIndexSetInteger(1,PLOT_SHIFT,_w_Shift); PlotIndexSetInteger(2,PLOT_SHIFT,_w_Shift); }
その結果、次の OnInit () 関数を取得します。
int OnInit(){ // preparing a multiplier to adjust the parameter in points if(Auto5Digits && (Digits()==3 || Digits()==5)){ mult=10; } else{ mult=1; } // preparing parameters PrepareParameters(); // loading the central line indicator LoadCentral(); // checking if the central line has been loaded successfully if(!central.CheckHandle()){ Alert("Central line error "+central.Name()); return(INIT_FAILED); } // loading the width calculating indicator LoadWidth(); // checking if the width calculating indicator has been loaded successfully if(!width.CheckHandle()){ Alert("Width error "+width.Name()); return(INIT_FAILED); } // showing hint on parameters Print("Central line parameters matching: "+central.Help()); Print("Width parameters matching: "+width.Help()); // setting the name ShortName="iUniChannel"; IndicatorSetString(INDICATOR_SHORTNAME,ShortName); // a standard part of the OnInit function SetIndexBuffer(0,Label1Buffer,INDICATOR_DATA); SetIndexBuffer(1,Label2Buffer,INDICATOR_DATA); SetIndexBuffer(2,Label3Buffer,INDICATOR_DATA); // setting labels and buffer shift SetStyles(); return(INIT_SUCCEEDED); }
この時点で、グラフィカルインターフェイスを持たないインジケーターが完了すると想定できます。 すべてのクラスとパラメータの操作をテストすることができ、その後、グラフィカルインターフェイスの作成に進むことができます。
テスト中、インジケータの操作で不便な点がありました。 1つは、中心線の期間と幅の計算期間を別々に管理しなければならないことです。 もちろん、このような管理は、インジケーターの可能性を広げることができますが、1つのパラメータを使用して2つの期間の同時制御が必要になる場合もあります。 中心線の3つの期間のいずれかに等しいチャネルの幅の期間を作るためにマイナーチェンジしてみましょう。 4つのオプションのうち1つが(URUniChannelDefines.mqh ファイルにある) 選択されます。
enum ELockTo{
LockTo_Off,
LockTo_Period1,
LockTo_Period2,
LockTo_Period3
};
LockTo_Off オプションを選択すると、期間は別々に調整されます。 その他の場合、w_Period パラメータの値は、中心線に対応する期間と等しくなります。 w_Period 変数の直後に ELockTo 型の変数を宣言してみましょう:
PrepareParameters () 関数の下部に次のコードを追加します。
switch(w_LockPeriod){ // depending on the lock type case LockTo_Period1: _w_Period=_c_Period1; break; case LockTo_Period2: _w_Period=_c_Period2; break; case LockTo_Period3: _w_Period=_c_Period3; break; }
もう一つの欠点は、パラメータに関するメッセージが「エキスパート」タブに表示され、その一部が表示されないということです。 情報を表示するようにコードを変更してみましょう。 Printではなく、独自の PrintColl () 関数を使用します。 2つのパラメータがこの関数に渡されます: キャプションとヘルプ文字列。 この関数では、ヘルプ文字列は別々にPrintされる部分に分割されます。
void PrintColl(string caption,string message){ Print(caption); // print the caption string res[]; // splitting the message int cnt=StringSplit(message,',',res); // printing the message in parts for(int i=0;i<cnt;i++){ StringTrimLeft(res[i]); Print(res[i]); } }
したがって、2つのヘルプPrintラインはOnInit () 関数で変更されます。
PrintColl("Central line parameters matching:",central.Help()); PrintColl("Width parameters matching:",width.Help());
インジケータの準備が整いました。添付ファイルの名前は "iUniChanhel" です。 今度はグラフィカルインターフェイスを作成しましょう。
グラフィカルインターフェイスクラスの作成
グラフィカルインタフェースは、ユニバーサルオシレーターのグラフィカルインタフェースに基づきます。 URUniOsc/UniOscGUI.mqh を UniChannel フォルダにコピーし、その名前を URUniChannelGUI.mqh に変更します。 ユニバーサルチャネルのグラフィカルインターフェイスは、ユニバーサルオシレーターのインターフェイスとは異なりますので、ここでは多くのタスクを行う必要があります。
主な違いは、ユニバーサルチャネルの2つのインジケーター (中心線とボーダー) の選択を必要とするので、2つの主要なインジケータの選択リストが必要です。 最初のリストには、中心線のパラメータを管理するためのコントロールが続きます。 次に、2番目のリストとボーダー線パラメータのコントロールが付属します。 したがって、2番目のリストには固定座標がないため、計算する必要があります。 2種類の選択リストに加えて、常にオフセット値の2つのエントリーフィールドを持つ必要があります。 フィールドの座標も固定されていません。 もう1つの重要な点は、w_LockPeriod パラメータに対応する変数を選択するためのリストです。 幅コントロールのグループに w_Period パラメータエントリーフィールドを表示する場合は、その他のドロップダウンリストを表示する必要があります。
まず、URUniChannelGUI.mqh ファイルの全般的な変更をラインいます。
1. 列挙型のファイルへのパス:
次のように置き換える必要があります。
2. ELockTo 列挙値を持つ配列を追加。
ELockTo e_lockto[]={LockTo_Off,LockTo_Period1,LockTo_Period2,LockTo_Period3};
3. ENUM_APPLIED_VOLUME と ENUM_STO_PRICE の列挙体を使用して配列を削除。
CUniOscControls クラスの変更に進みます。
中心線コントロールのクラス
1. CUniOscControls クラスを CUniChannelCentralControls に再命名。
2. 変数 m_volume と m_sto_price の宣言は、クラスから削除する必要があります。 したがって、コントロールに関連付けられているすべての SetPointers ()、hide ()、およびイベント () メソッドを削除します。
3. グループからの最後のコントロールの y 座標が記録される m_last_y 変数を追加します。 この変数の値を受け取るメソッドを追加します (GetLastY)。 FormHeight () メソッドを必要としないので、削除しましょう。 代わりに、子クラスのコントロールの数を返す ControlsCount () メソッドを追加する必要があります。 この数値は、フォームの高さを計算するために使用されます。
次に、親クラスを示します。
class CUniChannelCentralControls{ protected: CSpinInputBox * m_value1; // for period 1 CSpinInputBox * m_value2; // for period 2 CSpinInputBox * m_value3; // for period 3 CComBox * m_price; // for the price CComBox * m_method; // for the method int m_last_y; // the Y coordinate of the last control public: // getting the Y coordinate of the last control int GetLastY(){ return(m_last_y); } // method for passing object pointers to the object void SetPointers(CSpinInputBox & value1, CSpinInputBox & value2, CSpinInputBox & value3, CComBox & price, CComBox & method){ m_value1=GetPointer(value1); m_value2=GetPointer(value2); m_value3=GetPointer(value3); m_price=GetPointer(price); m_method=GetPointer(method); } // hiding the group of controls void Hide(){ m_value1.Hide(); m_value2.Hide(); m_value3.Hide(); m_price.Hide(); m_method.Hide(); } // event handling int Event(int id,long lparam,double dparam,string sparam){ int e1=m_value1.Event(id,lparam,dparam,sparam); int e2=m_value2.Event(id,lparam,dparam,sparam); int e3=m_value3.Event(id,lparam,dparam,sparam); int e4=m_price.Event(id,lparam,dparam,sparam); int e5=m_method.Event(id,lparam,dparam,sparam); if(e1!=0 || e2!=0 || e3!=0 || e4!=0 || e5!=0){ return(1); } return(0); } // methods for the initialization of controls (to change labels) virtual void InitControls(){ } // displaying the group of controls virtual void Show(int x,int y){ } // getting the number of controls in the group virtual int ControlsCount(){ return(0); } };
CUniOscControls_ATR クラスを変更してみましょう:
1. CUniChannelCentralControls_AMA に名前を変更し, AMAインジケータのクラスになります.
2. 表1の「パラメータ」列に従って、InitControls () メソッド内のすべてのコントロールを初期化し、show () メソッドですべてのコントロールの show () メソッドを呼び出します。 最後のコントロールの値を m_last_y 変数に代入する必要があります。
3. 今度は FormHeight () メソッドを削除し、代わりに ControlsCount () を追加します。
結果のクラスです:
class CUniChannelCentralControls_AMA:public CUniChannelCentralControls{ void InitControls(){ // initialization of controls m_value1.Init("c_value1",SPIN_BOX_WIDTH,1," ama_period"); m_value2.Init("c_value2",SPIN_BOX_WIDTH,1," fast_ma_period"); m_value3.Init("c_value3",SPIN_BOX_WIDTH,1," slow_ma_period"); } // display void Show(int x,int y){ m_value1.Show(x,y); y+=20; m_value2.Show(x,y); y+=20; m_value3.Show(x,y); y+=20; m_price.Show(x,y); m_last_y=y; } // getting the number of controls in the group int ControlsCount(){ return(4); } };
同様に、中心線に使用されるインジケーターの残りのクラスを作成し、不要なオシレータの子クラスをすべて削除します。
幅計算コントロールのクラス
CUniChannelCentralControls クラスに基づき、チャネル幅パラメータを管理するためのクラスを作成します。 CUniChannelCentralControls クラスのコピーを作成し、その名前を CUniChannelWidthControls に変更します。 このクラスでは、2つのエントリーフィールド (ピリオドと幅)、平均型と価格の2つの標準列挙、および w_LockPeriod パラメータ列挙が必要です。 その結果、次のクラスを取得します。
class CUniChannelWidthControls{ protected: CSpinInputBox * m_value1; // for the period CSpinInputBox * m_value2; // for the width CComBox * m_price; // for the price CComBox * m_method; // for the method CComBox * m_lockto; // for the lock type int m_last_y; // the Y coordinate of the last control public: // getting the Y coordinate of the last control int GetLastY(){ return(m_last_y); } // method for passing object pointers to the object void SetPointers(CSpinInputBox & value1, CSpinInputBox & value2, CComBox & price, CComBox & method, CComBox & lockto){ m_value1=GetPointer(value1); m_value2=GetPointer(value2); m_price=GetPointer(price); m_method=GetPointer(method); m_lockto=GetPointer(lockto); } // hiding the group of controls void Hide(){ m_value1.Hide(); m_value2.Hide(); m_price.Hide(); m_method.Hide(); } // event handling int Event(int id,long lparam,double dparam,string sparam){ int e1=m_value1.Event(id,lparam,dparam,sparam); int e2=m_value2.Event(id,lparam,dparam,sparam); int e4=m_price.Event(id,lparam,dparam,sparam); int e5=m_method.Event(id,lparam,dparam,sparam); int e6=m_lockto.Event(id,lparam,dparam,sparam); if(e1!=0 || e2!=0 || e4!=0 || e5!=0 || e6){ return(1); } return(0); } // methods for the initialization of controls (to change labels) virtual void InitControls(){ } // displaying the group of controls virtual void Show(int x,int y){ } // getting the number of controls in the group virtual int ControlsCount(){ return(0); } };
子クラスを作成してみましょう。 中心線クラスの主な相違点は、ピリオドエントリーフィールドの後に w_LockPeriod パラメータのドロップダウンリストを作成する必要があることです。 ATRを使用して幅の計算をします。
class CUniChannelWidthControls_ATR:public CUniChannelWidthControls{ void InitControls(){ // Control initialization m_value1.Init("w_value1",SPIN_BOX_WIDTH,1," period"); } // Displaying the group of controls void Show(int x,int y){ m_value1.Show(x,y); y+=20; m_lockto.Show(x,y); m_last_y=y; } // Getting the number of controls in the group int ControlsCount(){ return(2); } };
チャネル幅の計算の他のすべてのバリアントのクラスは、上記のいずれかに似ています。
URUniChannelGUI.mqh ファイルには、コントロールの2つの基本的なクラス、その子クラスとフォームクラスがあります。 後者は調整する必要があります。 サイズが大きく、ファイルの操作が不便な場合があるため、他のファイルのコントロールのクラスを準備します。 URUniChannel/CUniChannelCentralControls.mqh ファイルを作成し、CUniChannelCentralControls クラスとそのすべての子クラスをこのファイルに移動します。 また、追加のファイルを含めます。:
# include< URIncGUI_v4.mqh > # include <unichannel/unichanneldefines.mqh>
FORM_WIDTH、SPIN_BOX_WIDTH、COMBO_BOX_WIDTH は、URUniChannelDefines.mqh ファイルに移動されます。 その後、CUniChannelCentralControls ファイルは、エラーをチェックするためにコンパイルすることができます。 CUniChannelWidthControls クラスも別のファイルに移動する必要があります。 その後、フォームクラスを使用すると、より便利になります。
フォームクラス
URUniChannelGUI.mqh に新しく作成された2つのファイルを含めます。
# include <unichannel/cunichannelcentralcontrols.mqh> # include <unichannel/cunichannelwidthcontrols.mqh>
CUniOscForm を CUniChannelForm に再名前を付けます。 パブリックセクションでは、CUniOscControls 型ポインターを削除します。 代わりに、CUniChannelCentralControls と CUniChannelWidthControls の2つのポインター変数を宣言し、form クラスの他のコントロールを決定します。 次の変数は、パブリックセクションに配置されます。
CComBox m_c_cmb_main; // central line selection list CSpinInputBox m_c_value1; // input field for period 1 CSpinInputBox m_c_value2; // input field for period 2 CSpinInputBox m_c_value3; // input field for period 3 CComBox m_c_price; // price selection list CComBox m_c_method; // method selection list CSpinInputBox m_c_shift; // shift input fields CComBox m_w_cmb_main; // border selection list CSpinInputBox m_w_value1; // period input field CSpinInputBox m_w_value2; // width input field CComBox m_w_price; // price selection field CComBox m_w_method; // method selection field CComBox m_w_lockto; // lock option selection field CSpinInputBox m_w_shift; // shift input field // the group of central line controls CUniChannelCentralControls * m_central_controls; // the group of border controls CUniChannelWidthControls * m_width_controls;
MainProperties () メソッドでは、m_Name と m_Caption の変数の値を変更し、他のすべての変数は変わらないままです。
void MainProperties(){ m_Name = "UniChannelForm"; m_Width = FORM_WIDTH; m_Height = 150; m_Type = 0; m_Caption = "UniChannel"; m_Movable = true; m_Resizable = true; m_CloseButton = true; }
OnInitEvent () メソッドでは、不変のラベルを持つすべてのコントロール (選択したインジケーターに対応するコントロールのセット) の init () メソッドを呼び出し、ドロップダウンリストにします。
void OnInitEvent(){ // initialization of controls that are not included into the group m_c_cmb_main.Init("cb_c_main",COMBO_BOX_WIDTH," select central"); m_w_cmb_main.Init("cb_w_main",COMBO_BOX_WIDTH," select bands"); m_c_price.Init("c_price",COMBO_BOX_WIDTH," price"); m_c_method.Init("c_method",COMBO_BOX_WIDTH," method"); m_c_shift.Init("c_shift",COMBO_BOX_WIDTH,1," shift"); m_w_price.Init("w_price",COMBO_BOX_WIDTH," price"); m_w_method.Init("w_method",COMBO_BOX_WIDTH," method"); m_w_shift.Init("w_shift",COMBO_BOX_WIDTH,1," shift"); m_w_lockto.Init("cb_w_lockto",COMBO_BOX_WIDTH," lock period"); m_w_value2.Init("w_value2",SPIN_BOX_WIDTH,0.001," width"); // filling the drop-down lists for(int i=0;i<ArraySize(e_price);i++){ m_c_price.AddItem(EnumToString(e_price[i])); m_w_price.AddItem(EnumToString(e_price[i])); } for(int i=0;i<ArraySize(e_method);i++){ m_c_method.AddItem(EnumToString(e_method[i])); m_w_method.AddItem(EnumToString(e_method[i])); } for(int i=0;i<ArraySize(e_lockto);i++){ m_w_lockto.AddItem(EnumToString(e_lockto[i])); } // allow typing the shift value using keyboard m_c_shift.SetReadOnly(false); m_w_shift.SetReadOnly(false); }
OnShowEvent () メソッドでは、コントロールを表示します。 グループの表示後、Y座標を取得し、次のコントロールをこの座標に従って表示します。
void OnShowEvent(int aLeft, int aTop){ m_c_cmb_main.Show(aLeft+10,aTop+10); // central line type selection list m_central_controls.Show(aLeft+10,aTop+30); // a group of central line parameters controls int m_y=m_central_controls.GetLastY(); // getting the coordinate of the last control m_c_shift.Show(aLeft+10,m_y+20); // the shift parameter input field m_w_cmb_main.Show(aLeft+10,m_y+40); // the channel selection list m_width_controls.Show(aLeft+10,m_y+60); // a group of channel parameters controls m_y=m_width_controls.GetLastY(); // getting the coordinate of the last control m_w_value2.Show(aLeft+10,m_y+20); // the width input field m_w_shift.Show(aLeft+10,m_y+40); // the shift parameter input field }
コントロールは、OnHideEvent () メソッドで非表示にすることができます。
void OnHideEvent(){ m_c_cmb_main.Hide(); // central line type selection list m_central_controls.Hide(); // a group of central line parameters controls m_c_shift.Hide(); // the shift parameter input field m_w_cmb_main.Hide(); // channel selection field m_width_controls.Hide(); // a group of channel parameters controls m_w_shift.Hide(); // the shift parameter input field m_w_lockto.Hide(); // period lock type selection m_width_controls.Hide(); // width input field }
SetValues () メソッドで変更します。 メソッドパラメータのセットを変更すると、パラメータに対応する値をメソッド内のすべてのコントロールに設定します。
void SetValues(int c_value1, int c_value2, int c_value3, long c_method, long c_price, long c_shift, int w_value1, int w_value2, long w_method, long w_price, long w_lockto, long w_shift ){ // central line input field m_c_value1.SetValue(c_value1); m_c_value2.SetValue(c_value2); m_c_value3.SetValue(c_value3); m_c_shift.SetValue(c_shift); // channel parameters input fields m_w_value1.SetValue(w_value1); m_w_value2.SetValue(w_value2); m_w_shift.SetValue(w_shift); // display of selected types in the smoothing method selection lists for(int i=0;i<ArraySize(e_method);i++){ if(c_method==e_method[i]){ m_c_method.SetSelectedIndex(i); } if(w_method==e_method[i]){ m_w_method.SetSelectedIndex(i); } } // display of selected types in the price type selection lists for(int i=0;i<ArraySize(e_price);i++){ if(c_price==e_price[i]){ m_c_price.SetSelectedIndex(i); } if(w_price==e_price[i]){ m_w_price.SetSelectedIndex(i); } } // display of the selected type of channel period lock for(int i=0;i<ArraySize(e_lockto);i++){ if(w_lockto==e_lockto[i]){ m_w_lockto.SetSelectedIndex(i); break; } } }
settype () の代わりに、中心線の種類を設定するための SetCentralType () と、ボーダーの種類を設定するための SetWidthType () の2つのメソッドを作成します。 各メソッドの最後に、オブジェクトが作成されると、プロパティはコントロールに設定され、キーボードを使用して値をエントリーできます。 また、最小許容値を設定し、フォームの高さの計算のプライベートメソッドを呼び出します。
Метод SetCentralType():
void SetCentralType(long type){ // If an object has already been created, we need to delete it if(CheckPointer(m_central_controls)==POINTER_DYNAMIC){ delete(m_central_controls); m_central_controls=NULL; } switch((ECType)type){ // create an object depending on the selected class case UniCh_C_AMA: m_central_controls=new CUniChannelCentralControls_AMA(); break; case UniCh_C_DEMA: m_central_controls=new CUniChannelCentralControls_DEMA(); break; case UniCh_C_FrAMA: m_central_controls=new CUniChannelCentralControls_FrAMA(); break; case UniCh_C_MA: m_central_controls=new CUniChannelCentralControls_MA(); break; case UniCh_C_TEMA: m_central_controls=new CUniChannelCentralControls_TEMA(); break; case UniCh_C_VIDyA: m_central_controls=new CUniChannelCentralControls_VIDyA(); break; case UniCh_C_PrCh: m_central_controls=new CUniChannelCentralControls_PrCh(); break; } // passing pointers to control objects m_central_controls.SetPointers(m_c_value1,m_c_value2,m_c_value3,m_c_price,m_c_method); // initialization of group controls m_central_controls.InitControls(); // allowing entering values from keyboard m_c_value1.SetReadOnly(false); m_c_value2.SetReadOnly(false); m_c_value3.SetReadOnly(false); // setting the minimum allowed values m_c_value1.SetMinValue(1); m_c_value2.SetMinValue(1); m_c_value3.SetMinValue(1); // calculating the height of the form this.SolveHeight(); }
SetWidthType () メソッド:
void SetWidthType(long type){ // If an object has already been created, we need to delete it if(CheckPointer(m_width_controls)==POINTER_DYNAMIC){ delete(m_width_controls); m_width_controls=NULL; } switch((EWType)type){ // creating an object depending on the selected class case UniCh_W_ATR: m_width_controls=new CUniChannelWidthControls_ATR(); break; case UniCh_W_StdDev: m_width_controls=new CUniChannelWidthControls_StdDev(); break; case UniCh_W_Points: m_width_controls=new CUniChannelWidthControls_InPoints(); break; case UniCh_W_Percents: m_width_controls=new CUniChannelWidthControls_Envelopes(); break; case UniCh_W_PrCh: m_width_controls=new CUniChannelWidthControls_PrCh(); break; } // passing pointers to control objects m_width_controls.SetPointers(m_w_value1,m_w_value2,m_w_price,m_w_method); // initialization of group controls m_width_controls.InitControls(); // setting the minimum allowed values m_w_value1.SetReadOnly(false); m_w_value2.SetReadOnly(false); // setting the minimum allowed values m_w_value1.SetMinValue(1); m_w_value2.SetMinValue(0); // calculating the height of the form this.SolveHeight(); }
SetCentralType () および SetWidthType () メソッドのトレーリングストップには、フォームの高さを計算する SolveHeight () メソッドが呼び出されます。
void SolveHeight(){ // if both objects exist (central line and width) if(CheckPointer(m_central_controls)==POINTER_DYNAMIC && CheckPointer(m_width_controls)==POINTER_DYNAMIC){ m_Height=(m_width_controls.ControlsCount()+m_central_controls.ControlsCount()+6)*20+10; } }
インジケーターとグラフィカルユーザーインターフェイスの接続に進みます。
インジケータとグラフィカルインタフェースの接続
UniChannel インジケーターを iUniChannelGUI として保存します。 UniOscGUI inbdicator と同様に、そのプロパティウィンドウの上部に外部 UseGUI パラメータを追加します。 UseDefault と KeepPrev を追加した後、デフォルトで true に設定し、[プロパティ] ウィンドウに表示します。
input bool UseGUI = true; input bool UseDefault = true; input bool KeepPrev = true;
グラフィカルインターフェイスを含むファイル (インジケータークラスを含むファイルが含まれている場合):
OnInit () 関数の最下部で、gui ブートコードを追加します。 しかし、これを行う前に、中心線とボーダーの種類を持つ配列が必要です。 インジケータの外部パラメータの下にを追加:
// array of the central line types ECType ctype[]={ UniCh_C_AMA, UniCh_C_DEMA, UniCh_C_FrAMA, UniCh_C_MA, UniCh_C_TEMA, UniCh_C_VIDyA, UniCh_C_PrCh }; // array with the border types EWType wtype[]={ UniCh_W_ATR, UniCh_W_StdDev, UniCh_W_Points, UniCh_W_Percents, UniCh_W_PrCh };
また、フォームクラスへのポインターをここに追加します。
OnInit () 関数の最後に、GUIオブジェクトの作成を実装します。
if(UseGUI){ // creation and initialization of the form object frm=new CUniChannelForm(); frm.Init(); // auxiliary variables int ind1=0; int ind2=0; // search for the selected type of the central line in the array of central line types for(int i=0;i<ArraySize(ctype);i++){ frm.m_c_cmb_main.AddItem(EnumToString(ctype[i])); if(ctype[i]==_CentralType){ ind1=i; } } // search for the selected type of the channel border in the array of border types for(int i=0;i<ArraySize(wtype);i++){ frm.m_w_cmb_main.AddItem(EnumToString(wtype[i])); if(wtype[i]==_WidthType){ ind2=i; } } // showing the selected type of the central line in the list frm.m_c_cmb_main.SetSelectedIndex(ind1); // preparing controls corresponding to the type frm.SetCentralType(_CentralType); // showing the selected border type in the list frm.m_w_cmb_main.SetSelectedIndex(ind2); frm.SetWidthType(_WidthType); // setting values frm.SetValues( _c_Period1, _c_Period2, _c_Period3, _c_Method, _c_Price, _c_Shift, _w_Period, _w_Width, _w_Method, _w_Price, _w_LockPeriod, _w_Shift ); // setting the form properties frm.SetSubWindow(0); frm.SetPos(10,30); // showing the form frm.Show(); }
フォームオブジェクトの作成に加えて、インジケーターの選択リストがいっぱいになり、選択されたバリアントが割り当てられます。 また、コントロール内の他のすべての値を設定してみましょう。 その後、インジケーターをチャートに添付すると、コントロールを持つフォームが表示されます (図1)。
図1. ユニバーサルチャネルコントロールを持つフォーム
コントロールが正しく表示され、フォームボタンの操作を確認する必要があります。 6つの異なるイベントが OnChartEvent () 関数で処理されます。 イベントの処理は非常に複雑なので、別の関数が使用されます:
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { // form events if(frm.Event(id,lparam,dparam,sparam)==1){ EventForm(); } // selecting the central line type if(frm.m_c_cmb_main.Event(id,lparam,dparam,sparam)==1){ EventCentralTypeChange(); } // selecting the border type if(frm.m_w_cmb_main.Event(id,lparam,dparam,sparam)==1){ EventWidthTypeChange(); } // changing the central line parameters if(frm.m_central_controls.Event(id,lparam,dparam,sparam)==1){ EventCentralParametersChange(); } // changing the border parameters if(frm.m_width_controls.Event(id,lparam,dparam,sparam)==1){ EventWidthParametersChange(); } // changing the shift parameters if(frm.m_c_shift.Event(id,lparam,dparam,sparam)!=0 || frm.m_w_shift.Event(id,lparam,dparam,sparam) ){ EventShift(); } }
この関数をすべて検討してみましょう。 EventForm () 関数:
void EventForm(){ int win=ChartWindowFind(0,ShortName); // determining the indicator sub-window ChartIndicatorDelete(0,win,ShortName); // deleting the indicator ChartRedraw(); }
この関数は、十字ボタンを押してフォームを閉じると、インジケータウィンドウが短い名前で検索され、インジケーターが削除されるときに実行されます。
EventCentralTypeChange () 関数:
void EventCentralTypeChange(){ // getting a new type into the variable _CentralType=ctype[frm.m_c_cmb_main.SelectedIndex()]; // deleting an old object and creating a new one delete(central); LoadCentral(true); // checking the indicator loading if(!central.CheckHandle()){ Alert("Error while loading indicator "+central.Name()); } // setting offsets and buffer names SetStyles(); // setting a new type in the list frm.SetCentralType(ctype[frm.m_c_cmb_main.SelectedIndex()]); // updating the values of parameters on the form frm.SetValues( _c_Period1, _c_Period2, _c_Period3, _c_Method, _c_Price, _c_Shift, _w_Period, _w_Width, _w_Method, _w_Price, _w_LockPeriod, _w_Shift ); // refreshing the form frm.Refresh(); // starting the timer for the indicator re-calculation EventSetMillisecondTimer(100); }
この関数では、中心線インジケータの種類が変更されます。 まず、選択したインジケーターの種類が取得され、古いオブジェクトが削除され、新しいオブジェクトが作成されます。 新しいオブジェクトを作成する場合、そのパラメータの一部を変更することができます (UseDefault 関数のため)、SetValues () メソッドは、コントロールに新しい値を設定するために呼び出され、更新されます (refresh () メソッド)。 再計算時にタイマが起動し、インジケータの再計算が実行されます。
EventWidthTypeChange () 関数は EventCentralTypeChange () 関数に似ていますので、詳しくは解説しません。
EventCentralParametersChange () および EventWidthParametersChange () 関数は、パラメータの変化に対するインジケーターを提供します。 この関数は、中心となる点は同じです。 しかし、パラメータを修正するため、この関数は独自のユニークな関数を考慮されます。
void EventCentralParametersChange(){ // the variable indicates the need to restart the indicator of borders bool dolock=false; // changing the value of period 1 if((int)frm.m_c_value1.Value()>0){ // assigning a values received from the control to the variable _c_Period1=(int)frm.m_c_value1.Value(); // if period 1 is connected with the period of the width indicator if(_w_LockPeriod==LockTo_Period1){ // we set the value of period 1 to the variable with the width indicator period _w_Period=_c_Period1; // displaying it on the form frm.m_w_value1.SetValue(_w_Period); // indicating that the second indicator needs to be restarted dolock=true; } } // changing the value of period 2 similar to period 1 if((int)frm.m_c_value2.Value()>0){ _c_Period2=(int)frm.m_c_value2.Value(); if(_w_LockPeriod==LockTo_Period2){ _w_Period=_c_Period2; frm.m_w_value1.SetValue(_w_Period); dolock=true; } } // changing the value of period 3 similar to period 1 if((int)frm.m_c_value3.Value()>0){ _c_Period3=(int)frm.m_c_value3.Value(); if(_w_LockPeriod==LockTo_Period3){ _w_Period=_c_Period3; frm.m_w_value1.SetValue(_w_Period); dolock=true; } } // changing the method if(frm.m_c_method.SelectedIndex()!=-1){ _c_Method=e_method[frm.m_c_method.SelectedIndex()]; } // changing the price if(frm.m_c_price.SelectedIndex()!=-1){ _c_Price=e_price[frm.m_c_price.SelectedIndex()]; } // deleting an old object and creating a new one delete(central); LoadCentral(false); if(!central.CheckHandle()){ Alert("Error while loading indicator "+central.Name()); } // deleting and creating a new object of the second indicator if(dolock){ delete(width); LoadWidth(false); if(!width.CheckHandle()){ Alert("Error while loading indicator "+width.Name()); } } // setting offsets and buffer names SetStyles(); // starting the timer for the indicator re-calculation EventSetMillisecondTimer(100); }
この関数は、3つの期間のいずれかが変更されると、パラメータのチェックが実行されます。 ボーダーインジケータのパラメータが変更され、フォーム上で更新され、true が dolock 変数に割り当てられます。 最後に、古いインジケーターオブジェクトが削除され、新しいものが作成され、dolock 変数が true と等しい場合は、境界線のオブジェクトが削除されます。 その後、タイマーが開始し、インジケーターが再計算します。
void EventWidthParametersChange(){ // the variable indicates the need to restart the indicator of the central line bool dolock=false; // changing the period if((int)frm.m_w_value1.Value()>0){ // assigning a values received from the control to the variable _w_Period=(int)frm.m_w_value1.Value(); // performing the lock // the width parameter is connected with the first period of the central line if(_w_LockPeriod==LockTo_Period1){ // assigning a new value to the variable of the central line indicator _c_Period1=_w_Period; // updating the value on the form frm.m_c_value1.SetValue(_c_Period1); // indicating the need to restart the width indicator dolock=true; } else if(_w_LockPeriod==LockTo_Period2){ // if locking with period 2 _c_Period2=_w_Period; frm.m_c_value2.SetValue(_c_Period2); dolock=true; } else if(_w_LockPeriod==LockTo_Period3){ // if locking with period 3 _c_Period3=_w_Period; frm.m_c_value3.SetValue(_c_Period3); dolock=true; } } // changing the channel width parameter if((double)frm.m_w_value2.Value()>0){ _w_Width=(double)frm.m_w_value2.Value(); } // changing the method if(frm.m_w_method.SelectedIndex()!=-1){ _w_Method=e_method[frm.m_w_method.SelectedIndex()]; } // changing the price if(frm.m_w_price.SelectedIndex()!=-1){ _w_Price=e_price[frm.m_w_price.SelectedIndex()]; } // the event of a change in the lock type selection list if(frm.m_w_lockto.SelectedIndex()>=0){ // assigning a values received from the control to the variable _w_LockPeriod=e_lockto[frm.m_w_lockto.SelectedIndex()]; // if locking with some of the periods is selected, // its value is copied and the form is refreshed if(_w_LockPeriod==LockTo_Period1){ _w_Period=_c_Period1; frm.m_w_value1.SetValue(_w_Period); } else if(_w_LockPeriod==LockTo_Period2){ _w_Period=_c_Period2; frm.m_w_value1.SetValue(_w_Period); } else if(_w_LockPeriod==LockTo_Period3){ _w_Period=_c_Period3; frm.m_w_value1.SetValue(_w_Period); } } // deleting an old object and creating a new one delete(width); LoadWidth(false); if(!width.CheckHandle()){ Alert("Error while loading indicator "+width.Name()); } // deleting and creating a new object of the second indicator if(dolock){ delete(central); LoadCentral(false); if(!central.CheckHandle()){ Alert("Error while loading indicator "+central.Name()); } } // setting offsets and buffer names SetStyles(); // starting the timer for the indicator re-calculation EventSetMillisecondTimer(100); }
この関数は、期間を変更する際チェックされ、必要に応じて中心線インジケータに対応する期間が変更されます。 選択リストが受信された場合、中心線インジケータの適切な変数からの値がボーダーインジケータ期間の変数に割り当てられます。
シフト値の変更のイベントの処理は非常に簡単です:
void EventShift(){ // receiving new values in the variables _c_Shift=(int)frm.m_c_shift.Value(); _w_Shift=(int)frm.m_w_shift.Value(); // setting new styles SetStyles(); // refreshing the chart ChartRedraw(); }
コントロールの値が変数に代入され、setstyles () が呼び出され、チャートが更新されます。
この時点で、グラフィカルインターフェイスを持つインジケータは、ほぼ準備が整いました。
インジケーターテスト中に次の欠陥が検出されました。 外部 UseDefault パラメータが有効で、ピリオドロックが使用された場合、ロックが失敗しました。 これは、2番目のインジケータ (幅インジケータ) をロードするときに、パラメータの変更がコンストラクタで実行されるという事実に基づいています。 このバグを修正するために、幅インジケータの特定の子クラスを変更しなければなりません。 オプションのパラメータ ' ロック ' は、CChannelUni_Calculate_ATR、CChannelUni_Calculate_StdDev、および CChannelUni_Calculate_PriceChannel のコンストラクタに追加されました。 デフォルト値は false です。 (パラメータがクラスに渡されない場合、すべては変更なしで動作します)。 locked = true と use_default = true の場合、コンストラクタ内のピリオドパラメータは変更されません (locked = true)。 CChannelUni_Calculate_ATR クラスの一部です:
if(use_default){ if(keep_previous){ if(ma_period==-1 && !locked)ma_period=14; // change if(ch_width==-1)ch_width=2; } else{ if(!locked)ma_period=14; // change ch_width=2; } }
デフォルト値は、ロックされた変数が false に設定した場合にのみ ma_period に割り当てられます。 LoadWidth () 関数は応じています。 ロック ' の値は、関数の先頭で計算されます。
この変数は、オブジェクトの作成時にクラスのコンストラクタに渡されます。
ユニバーサルオシレーターで行われたように、ここでは、カラースキームを変更し、時間枠を変更するときにインジケータのパラメータの保存を提供する関数を追加します。 ユニバーサルオシレーターの作成時に考慮したため、配色パターンの使用については説明しません。 インジケーターパラメータの保存を提供します。
インジケーターの OnDeinit () 関数は、チャートの変更により初期化が実行された場合、パラメータの値を持つグラフィカルオブジェクトを作成します。 チャートの可視性の外で、グラフィカルオブジェクトを作成してみましょう:
void SaveOrDeleteParameters(const int reason){ // if it is not chart change, we should delete graphical objects if(reason!=REASON_CHARTCHANGE){ ObjectDelete(0,"_CentralType"); ObjectDelete(0,"_c_Period1"); ObjectDelete(0,"_c_Period2"); ObjectDelete(0,"_c_Period3"); ObjectDelete(0,"_c_Shift"); ObjectDelete(0,"_c_Method"); ObjectDelete(0,"_c_Price"); ObjectDelete(0,"_WidthType"); ObjectDelete(0,"_w_Period"); ObjectDelete(0,"_w_LockPeriod"); ObjectDelete(0,"_w_Shift"); ObjectDelete(0,"_w_Method"); ObjectDelete(0,"_w_Price"); ObjectDelete(0,"_w_Width"); } else{ // when changing the chart, we create graphical objects with the values of parameters SaveParameter("_CentralType",(string)_CentralType); SaveParameter("_c_Period1",(string)_c_Period1); SaveParameter("_c_Period2",(string)_c_Period2); SaveParameter("_c_Period3",(string)_c_Period3); SaveParameter("_c_Shift",(string)_c_Shift); SaveParameter("_c_Method",(string)_c_Method); SaveParameter("_c_Price",(string)_c_Price); SaveParameter("_WidthType",(string)_WidthType); SaveParameter("_w_Period",(string)_w_Period); SaveParameter("_w_LockPeriod",(string)_w_LockPeriod); SaveParameter("_w_Shift",(string)_w_Shift); SaveParameter("_w_Method",(string)_w_Method); SaveParameter("_w_Price",(string)_w_Price); SaveParameter("_w_Width",(string)_w_Width); } } // an auxiliary function for saving one parameter in a graphical object void SaveParameter(string name,string value){ if(ObjectFind(0,name)==-1){ ObjectCreate(0,name,OBJ_LABEL,0,0,0); ObjectSetInteger(0,name,OBJPROP_XDISTANCE,0); ObjectSetInteger(0,name,OBJPROP_YDISTANCE,-30); } ObjectSetString(0,name,OBJPROP_TEXT,value); }
oninit () 関数では、PrepareParameters () 関数の呼び出し直後に、LoadSavedParameters () 関数を呼び出します。
bool LoadSavedParameters(){ // if all objects with parameters exist if(ObjectFind(0,"_CentralType")==0 && ObjectFind(0,"_c_Period1")==0 && ObjectFind(0,"_c_Period2")==0 && ObjectFind(0,"_c_Period3")==0 && ObjectFind(0,"_c_Shift")==0 && ObjectFind(0,"_c_Method")==0 && ObjectFind(0,"_c_Price")==0 && ObjectFind(0,"_WidthType")==0 && ObjectFind(0,"_w_Period")==0 && ObjectFind(0,"_w_LockPeriod")==0 && ObjectFind(0,"_w_Shift")==0 && ObjectFind(0,"_w_Method")==0 && ObjectFind(0,"_w_Price")==0 && ObjectFind(0,"_w_Width")==0 ){ // getting values from graphical objects _CentralType=(ECType)ObjectGetString(0,"_CentralType",OBJPROP_TEXT); _c_Period1=(int)ObjectGetString(0,"_c_Period1",OBJPROP_TEXT); _c_Period2=(int)ObjectGetString(0,"_c_Period2",OBJPROP_TEXT); _c_Period3=(int)ObjectGetString(0,"_c_Period3",OBJPROP_TEXT); _c_Shift=(int)ObjectGetString(0,"_c_Shift",OBJPROP_TEXT); _c_Method=(long)ObjectGetString(0,"_c_Method",OBJPROP_TEXT); _c_Price=(long)ObjectGetString(0,"_c_Price",OBJPROP_TEXT); _WidthType=(EWType)ObjectGetString(0,"_WidthType",OBJPROP_TEXT); _w_Period=(int)ObjectGetString(0,"_w_Period",OBJPROP_TEXT); _w_LockPeriod=(long)ObjectGetString(0,"_w_LockPeriod",OBJPROP_TEXT); _w_Shift=(int)ObjectGetString(0,"_w_Shift",OBJPROP_TEXT); _w_Method=(long)ObjectGetString(0,"_w_Method",OBJPROP_TEXT); _w_Price=(long)ObjectGetString(0,"_w_Price",OBJPROP_TEXT); _w_Width=(double)ObjectGetString(0,"_w_Width",OBJPROP_TEXT); return(true); } else{ return(false); } }
この関数は、オブジェクトが存在するかどうかをチェックします。 存在する場合、オブジェクトが使用されている場合、true を返します。 この関数が true を返した場合、LoadCentral () 関数と LoadWidth () は false パラメータを使用して呼び出す必要があります (デフォルトのパラメータの設定を防ぐため)。 oninit () 関数の断片:
bool ChartCange=LoadSavedParameters();
LoadCentral(!ChartCange);
LoadWidth () 関数は、同じ方法で呼び出されます。
ユニバーサルチャネルの作成が完全に完了しました。
結論
ユニバーサルオシレーターから大量のコードを使用するにもかかわらず、ユニバーサルチャネルの作成にはまだかなりのタスクが必要です。 ユニバーサルオシレーターの主な違いは、2つの独立したユニットの存在です。つまり、中心線とチャネルの境界線です。 2倍難しくなりました。 ユニバーサルチャネルには、周期ロック関数によって接続される、より複雑なパラメータ変更アルゴリズムがあります。 新しいインジケータの読み込みは、2つのインジケータが使用されるため、より複雑になりました。 また、新しい関数を追加し、時間枠を切り替えるときにパラメータを保存します。 その結果、有用なインジケーターができました。 さらに、このインジケータは、チャネルの関数を大幅に拡張し、中心線とチャネル境界の構築メソッドを別々に選択することができます。 可能な組み合わせは多岐にわたります。 グラフィカルインターフェイスを使用したインジケータアプリケーションは、視覚的にすべての組み合わせを分析することができます。
添付
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/2888
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索