
サポート/レジスタンスレベルの表示
はじめに
本稿では MetaTrader 4 プログラムにおけるサポート/レジスタンスレベルの検出および表示について取り上げます。シンプルなアルゴリズムに基づき、便利で万能なインディケータ FindLevels はシンボルチャート内で水平のサポートラインを作り出します。以下でそれが確認できます。
本稿ではまた、一つのワークスペース内の異なるタイムフレームからもたらされる結果を表示する、シンプルなインディケータの作成という有用なテーマにも取り組みます。以下はその例です。
1番目のインディケータは30分足クオートを基にサポートレベル(濃いベージュ色の線)を表示しています。同じウィンドウで実行されている2番目のインディケータは、15分足のタイムフレーム(薄い紫の破線)を基に30分足レベルの上に表示しています。詳細については『インディケータの相互作用』項を見てください。
本稿はサポートレベルを検出するためのスクリプトを作成することに関する記事の続編ですが、本稿はプログラミングと MetaTrader 4 プラットフォーム利用の上級者だと自覚している方のために書かれている点が異なります。それが、初心者や、本稿がむつかしすぎると思う方々に私の前稿 A Method of Drawing the Support/Resistance Levelsをお薦めする理由です。
理論的再検証
サポート/レジスタンスレベルの検出アルゴリズムを説明します。それはのちに FindLevels インディケータで実行されるものです。サポート/レジスタンスレベルはなんらかの力によりクロスできない価格値です。それは大口プレーヤーの影響やこの領域における高額のストップロス注文といった、心理的な基準によって引き起こされる可能性があります。クオートがこのラインをクロスするのはサポートしない他のラインよりもずっと頻度の低いものであることは明らかです。このことについては数多くのトレーディング本で証拠を見つけることができます。
このことを利用するため、価格それぞれをクロスするバー数を計算する必要があります。以下は前稿で述べられた計算結果です。
この絵の横軸は価格、縦軸はその価格をクロスしているバー数を示しています。絵でみてわかるように、チャートには数多くの極小値があります。極小値はノンゼロ間隔に属し、それ自体はこの間隔の最小値です。ここで一定の特性に従って極消小値を選択する必要があります。
まず、定数 MaxR を設定します。これはエリア半径です。極小値が MaxR 半径エリアに属する最小値でなければ、それはわれわれのタスクにあてはまりません。次に、MaxCrossesLevel パラメータを設定します。関数の最大値と最小値との差が MaxR エリアの MaxCrossesLevel 分より小ければ、この極小値は十分有意ではないため表示しません。これはサポート/レジスタンスレベル検出のメカニズムです。このシンプルなアルゴリズムに続いて、インディケータを書きます。
補助関数
上で説明したように、FindLevels インディケータはどんなタイムフレームのからのクオートでも処理するようにできています。 タイムフレームはユーザーが設定します( FindLevels 変数)。コードのシンをプルにするために、説明を必要としない簡単な関数を 2 つ設定します。
double prLow(int i) { return (iLow(NULL,TimePeriod,i)); } double prHigh(int i) { return (iHigh(NULL,TimePeriod,i)); }
3番目、4番目の関数はサポートレベル、その幅、色、タイムフレームによって決まる表示モードを便利に表示するために必要なものです。
int Period2Int(int TmPeriod) { switch(TmPeriod) { case PERIOD_M1 : return(0); case PERIOD_M5 : return(1); case PERIOD_M15 : return(2); case PERIOD_M30 : return(3); case PERIOD_H1 : return(4); case PERIOD_H4 : return(5); case PERIOD_D1 : return(6); case PERIOD_W1 : return(7); case PERIOD_MN1 : return(8); } return (0); } string Period2AlpthabetString(int TmPeriod) { return(Alphabet[Period2Int(TmPeriod)]); }
関数 Period2AlphabetString() を設定する意味は『インディケータの相互作用』項で説明があります。またPeriod2Int() 関数の用途は次の項で明らかになります。
インディケータの作成
ユーザーによって設定される外部変数から始めます。
extern int MaxLimit = 1000; extern int MaxCrossesLevel = 10; extern double MaxR = 0.001; extern int TimePeriod = 0; extern color LineColor = White; extern int LineWidth = 0; extern int LineStyle = 0;
- MaxLimit -使用されている履歴バーの数量
- MaxCrossesLevel -極大値と極小値間の最小差(詳細は『理論的再検討』項を参照ください)
- MaxR -最小値が検出されるエリア半径
- TimePeriod -サポートレベルを検出するタイムフレームデフォルトでは、マッピングウィンドウのタイムフレームになっています。
- LineColor -表示される線色
- LineWidth -線幅、デフォルトでは0
- LineStyle -線スタイル、デフォルトでは0
LineColor、LineWidth、 LineStyle の値がデフォルトのようにユーザーによって設定されるなら、Init プロシージャを処理している間、それらをタイムフレームに依存する別の値に変更します。そうすると、異なるタイムフレームからの線の表示は同じではなく、それらを簡単に区別することができるようになります。
int init() { if(TimePeriod == 0) TimePeriod = Period(); if(TimePeriod != 0 && LineWidth == 0) if(Period2Int(TimePeriod) - Period2Int(Period()) >= 0) LineWidth = Widths[Period2Int(TimePeriod) - Period2Int(Period())]; else { LineWidth = 0; if(LineStyle == 0) LineStyle = STYLE_DASH; } if(TimePeriod != 0 && LineColor == White) LineColor = Colors[Period2Int(TimePeriod)]; return(0); }
デフォルトで設定されているなら、1行目では TimePeriod 値を設定します。そして線幅を決めます。チャート(マッピングウィンドウ)のタイムフレームに関連するTimePeriod 値が多いほど、線幅は広くなります。TimePeriod がチャート期間より小さければ、線幅は 0 となり線は破線します。期間にはそれぞれ独自の色がついています。
配列 Colors[] および Width[] は以下の方法で定義されます。
color Colors[] = {Red,Maroon, Sienna, OrangeRed, Purple,I ndigo, DarkViolet, MediumBlue, DarkSlateGray}; int Widths[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
残りの変数を定義します。
int CrossBarsNum[]; bool CrossBarsMin[]; double d1Num = 0.0, d2Num = 0.0; datetime TMaxI = 0;
- 配列 CrossBarsNum[] -それぞれの価格に対するバー数量を示します。
- CrossBarsMin[] -設定価格が極小値であるか否かということに対応しています。
- d1Num および d2Num -0から MaxLimit までのバー間隔に属すす高値と安値
- TMaxI 最終処理済みバーの時刻を示します。
#define MaxLines 1000 string LineName[MaxLines]; int LineIndex = 0;
MaxLines -みなさんが作成する線の高値
LineName[] -名前の配列
LineIndex -配列 LineName[] 内の空セルのインデックス
関数 start() に渡します。
int counted_bars = IndicatorCounted(); int limit = MathMin(Bars - counted_bars, MaxLimit); double d1 = prLow(iLowest(NULL, TimePeriod, MODE_LOW, limit, 0)); double d2 = prHigh(iHighest(NULL, TimePeriod, MODE_HIGH, limit, 0));
最後にインディケータをフェッチして以来変更されていないバーの数量を用いてリミット変数を計算します。d1 および d2 は 0 から限度までの間隔での価格の最小値と最大値です。
if(d1Num != d1 || d2Num != d2) { ArrayResize(CrossBarsNum, (d2 - d1)*10000); ArrayResize(CrossBarsMin, (d2 - d1)*10000); if(d1Num != d1 && d1Num != 0.0) { ArrayCopy(CrossBarsNum, CrossBarsNum, 0, (d1Num - d1)*10000); ArrayCopy(CrossBarsMin, CrossBarsMin, 0, (d1Num - d1)*10000); } d1Num = d1; d2Num = d2; }
インディケータ処理中、配列 CrossBarsNum[] と CrossBarsMin[] を用いて換算される価格差は変更可能です。それが起こるたびに、配列内のセル数を増やし、必要に応じて右に移動する必要があります。通常それが起こるのは、新しい値 d1 と d2 が関数 start() を前回起動したときに取得された変数 d1Num、d2Num と一致しないときです。
for(double d = d1; d <= d2; d += 0.0001) { int di = (d - d1)*10000; for(int i = 1; i < limit; i++) if(d > prLow(i) && d < prHigh(i)) CrossBarsNum[di]++; if(Time[limit] != TMaxI&&TMaxI != 0) if(d > prLow(iBarShift(NULL, 0, TMaxI)) && d < prHigh(iBarShift(NULL, 0, TMaxI))) CrossBarsNum[di]--; } TMaxI = Time[limit] - 1;
われわれの配列が必要なディメンションに一致していることが確認できたら、それぞれの価格に対する新規バーの計算を開始し、バーが価格レベルをクロスするとき CrossBarsNum[] 値を増やします。新規バーが絶えず出現するので、古いバーは [0 : limit] 間隔から除外されます。このため、そのようなバーをチェックし、交点である場合は CrossBarsNum[] 値を減らす必要があります。それから最終計算済みバー時刻を TmaxI 変数に割り当てます。
double l = MaxR*10000; for(d = d1 + MaxR; d <= d2 - MaxR; d += 0.0001) { di = (d - d1)*10000; if(!CrossBarsMin[di] && CrossBarsNum[ArrayMaximum(CrossBarsNum, 2*l, di - l)] - CrossBarsNum[ArrayMinimum(CrossBarsNum, 2*l, di - l)] > MaxCrossesLevel && CrossBarsNum[di] == CrossBarsNum[ArrayMinimum(CrossBarsNum, 2*l, di - l)] && CrossBarsNum[di-1] != CrossBarsNum[ArrayMinimum(CrossBarsNum, 2*l, di - l)]) { CrossBarsMin[di] = true; LineName[LineIndex] = Period2AlpthabetString(TimePeriod) + TimePeriod + "_" + d; ObjectCreate(LineName[LineIndex], OBJ_HLINE, 0, 0, d); ObjectSet(LineName[LineIndex], OBJPROP_COLOR, LineColor); ObjectSet(LineName[LineIndex], OBJPROP_WIDTH, LineWidth); ObjectSet(LineName[LineIndex], OBJPROP_STYLE, LineStyle); LineIndex++; } if(CrossBarsMin[di] && CrossBarsNum[di] != CrossBarsNum[ArrayMinimum(CrossBarsNum, 2*l, di - l)]) { CrossBarsMin[di] = false; ObjectDelete(Period2AlpthabetString(TimePeriod) + TimePeriod + "_" + d); } }
新しい極小値を決め、もはや極小値ではないとわかる古いものを削除するため、プロシージャの末尾で今一度 CrossBarsMin[] 配列をモニターします。極小値でありうる値は複数あるため(CrossBarsMin[] 配列には一致する値が複数あり、それらはすべて極小値なのです)、そのうちの一つだけを得る必要があります。最も低い価格の極小値を使用します。
CrossBarsNum[di] == CrossBarsNum[ArrayMinimum(CrossBarsNum, 2*l, di - l)] && CrossBarsNum[di-1]!= CrossBarsNum[ArrayMinimum(CrossBarsNum, 2*l, di - l)]
新しいグラフィカルオブジェクト-水平ライン、を作成するのにむつかしいことはありません。この線についての特性を設定します。:幅、スタイル、色など以前に Init プロシージャで作成されたものですもはやサポートレベルではないとわかるレベルを検索するのにむつかしいことは何もありませn。明確になっていないことが一つだけあります。:オブジェクト名の中でPeriod2AlpthabetString(TimePeriod) 関数を使用する理由および使用目的です。次の段落でこの問題について説明をします。それは以前に何度も話されていることです。
インディケータの相互作用
本稿冒頭で述べられているように、FindLevels インディケータはチャート内の複数のタイムフレームのサポートレベルを表示するために作成されています。これを達成するためには以下のものが必要です。
インディケータを複数回起動することが可能で、インディケータは期間を伴うインプットデータを持つ必要があります。
線は異なっており、サポートレベルがそれぞれどの期間に属するか簡単に決める必要があります。
線はすべて長短期間両方でトレースされる必要があります。
第1ポイントは問題を起こしません。グローバル変数はありません。期間に対しグラフィカルオブジェクト名はそれぞれ異なります。それはオブジェクト名の中に期間が入っているからです(たとえば、"f30_1.25600000 では30が期間です)。そのため、複数のインディケータを起動しても衝突は起こりません。
2番目のポイントは正常に実行されます。線がそれぞれ期間に応じて独自の色をしているためです(LineColor=Colors[Period2Int(TimePeriod)])。
これで残りは第3のポイントです。ある線が5分足チャートのサポートラインであるとわかれば、それはまた30分足チャートのサポートラインでもある、というのはきわめて論理的です。こういった線が価格で衝突し、幅が同じである場合、そのうちの1本は見えないのです。異なるタイムフレームの線幅が異なっているのはそのためです。長いタイムフレームのサポートレベルを短いタイムフレームの線よりも幅広くします。それはひじょうに合理的です。なぜなら長い間隔にある線は有意性が高いからです。
線表示の適切な優先順位を設定する必要があります。細い線は最後に表示し、太い線に重ねます。そうするとはっきりと見えます。MetaTrader 4 プログラムでは、オブジェクトはアルファベット順で表示されます。そのため、長期間の線の名前は短期間の線の名前よりもアルファベット順で先にくる必要があります。それが期間に応じてラテンアルファベット文字を設定する関数を作成した理由です。
string Period2AlpthabetString(int TmPeriod) { return (Alphabet[Period2Int(TmPeriod)]); }
アルファベットは逆順でのラテン文字の配列です。サポートレベルそれぞれのフルネームは次のようなものです。:Period2AlpthabetString(TimePeriod)+TimePeriod+"_"+d
理解を促すために、記事冒頭のスクリーンショットを参照します。
まとめ
インディケータ検証により、それが正常に動作することが示されました。異なるタイムフレームからデータを表示することができるので、使い勝手がよいですはよくなっています。検証期間は、インディケータが各 TimePeriod に対して 3~10 のサポートレベルを表示すると、より便利であることを示しました。これを行うには、対応する入力エントリー MaxR と MaxCrossesLevel を選択する必要があります。検証中、MaxR は短いタイムフレームに対する 0.0003 から、長いタイムフレームに対する 0.002 まで変化しました。MaxCrossesLevel は 3 から 20 まで変化しました。おそらくもっとも有意なサポートレベルの特定額を表示するようインディケータを構成すると役に立つかもしれませんが、そうするとコードが複雑になってしまうでしょう。私のインディケータを好んでいただける方はご自身でもそれを簡単に行うことができると思います。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1440



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