
Candlestick Trend Constraintモデルの構築(第1回):EAとテクニカル指標について
内容
- はじめに
- 上位時間枠でのローソク足の解剖学
- ストラテジー開発(移動平均クロスオーバー)とコード
- 制約の正当性とその適用とコード
- コードを使用するメリット
- 結論
はじめに
市場トレンドを定義するために移動平均線を使用する代わりに、より長居時間枠のローソク足の強気または弱気の性質は、市場の方向性について貴重な洞察を提供することができます。例えば、D1やH4のローソク足の中には、M1の時間枠で起きている重要な活動があり、その形成を形成するティックさえあります。強気なD1ローソク足がもたらす買いのチャンスを生かし、弱気な局面では売ることで、トレーダーは優位に立つことができます。これをより短い時間枠のネイティブテクニカル指標と組み合わせることで、エントリポイントをピンポイントで特定し、トレーダーに戦略的な優位性を提供します。強気の日足ローソク足を扱う場合、トレーダーは自信を持ってトレンドに乗る前に、有利な市場条件が揃うのを辛抱強く待つべきです。
この記事では、MQL5コードを使用して現在のローソク足を効果的に強気か弱気に分類し、弱気のときだけ売り、強気のときだけ買うという条件を確立することを目的としています。
このモデルは、シグナル生成器を現在のローソク足のトレンドに沿ったシグナルの生成に限定することを目的としています。体の大きさによって特定の生き物が庭に入るのを制限し、他の生き物は許可するフェンスを考えてみましょう。私たちは同様の概念を応用して、選択されたシグナルをフィルタリングし、最も最適なものだけを残すようにしています。このモデルは、より長い時間枠のローソク足と市場トレンドを分析することによってこれを達成し、効果的に、優勢なトレンドに適合するシグナルのみが通過することを許す仮想バリアを作り出します。この選択的濾過プロセスは、生成されたシグナルの精度と信頼性を高め、最も有利な取引機会のみがユーザーに提示されることを保証します。
この記事の最後に、次のことができるはずです。
- D1ローソク足全体をミクロの時間枠で表示し、プライスアクションを理解する
- 上位時間枠Trend Constraint条件を含むMAクロスオーバー指標バッファを作成する
- 与えられた戦略から最適なシグナルを選別する概念を理解する
上位時間枠でのローソク足の解剖学
図1.1:Boom 500指数合成のM5時間枠で見たD1の解剖学
上の画像では、左端にD1ローソク足の赤いバー、右端に日足で区切られたM5プライスアクションが描かれています。明確な下降トレンドが明白であり、日足ローソク足の弱気な性質に支えられ、売りの可能性が高いことを示しています。この設定では、日足のローソク足に合わせて取引をおこなうことを重視しており、上位時間枠のトレンドの発生から制約のアイデアが生まれたことを反映しています。
ストラテジー開発(移動平均クロスオーバー)
取引戦略の開発には、分析、テスト、そして継続的な改良の組み合わせが必要です。成功する取引戦略は、市場を十分に理解し、従うべき明確なルールとガイドラインに基づいていなければなりません。新たなトレンドや機会に適応するためには、市場環境の変化に応じて戦略を常にモニターし、調整することが重要です。継続的にデータを分析し、さまざまなアプローチをバックテストし、必要に応じて調整を加えることで、トレーダーは市場で成功する可能性を高めることができます。
MAクロスオーバー戦略に進む前に、戦略開発における重要なヒントを以下に要約します。
- 目的とリスク許容度の定義
- 市場の理解
- 取引スタイルの選択
- エントリ・エグジットルールの開発
- リスク管理戦略の実施
- 戦略のバックテスト
- 最適化と改良
- 本番前のデモ取引
- 監視と評価
- ストラテジーの条件を設定する(この場合、EMA7がEMA21を上回るか下回るか)
- 指標の表示スタイルを設定する(MetaTrader 5で利用可能な矢印または任意の幾何学的形状)
- (オプション)指標がユーザーによってカスタマイズ可能である場合、入力を設定する
この記事のメイントピックである制約アルゴリズムに焦点を当てるため、あまり説明せずに最終的なコードをここに掲載することにしました。以下のプログラムは、売買シグナルをコンパイルして生成する準備ができています。コードの後、mt5チャートで結果を分析し、制約アルゴリズムが対処する問題を特定します。
//Indicator Name: Trend Constraint #property copyright "Clemence Benjamin" #property link "https://mql5.com" #property version "1.00" #property description "A model that seek to produce sell signal when D1 candle is Bearish only and buy signal when it is Bullish" //--- indicator settings #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 #property indicator_type1 DRAW_ARROW #property indicator_width1 5 #property indicator_color1 0xFFAA00 #property indicator_label1 "Buy" #property indicator_type2 DRAW_ARROW #property indicator_width2 5 #property indicator_color2 0x0000FF #property indicator_label2 "Sell" #define PLOT_MAXIMUM_BARS_BACK 5000 #define OMIT_OLDEST_BARS 50 //--- indicator buffers double Buffer1[]; double Buffer2[]; double myPoint; //initialized in OnInit int MA_handle; double MA[]; int MA_handle2; double MA2[]; double Low[]; double High[]; void myAlert(string type, string message) { if(type == "print") Print(message); else if(type == "error") { Print(type+" | Trend constraint @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } else if(type == "order") { } else if(type == "modify") { } } // Custom indicator initialization function int OnInit() { SetIndexBuffer(0, Buffer1); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(0, PLOT_ARROW, 241); SetIndexBuffer(1, Buffer2); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(1, PLOT_ARROW, 242); //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; } MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle < 0) { Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle2 = iMA(NULL, PERIOD_CURRENT, 21, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle2 < 0) { Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } return(INIT_SUCCEEDED); } //Custom indicator iteration function int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], const double& high[], const double& low[], const double& close[], const long& tick_volume[], const long& volume[], const int& spread[]) { int limit = rates_total - prev_calculated; //--- counting from 0 to rates_total ArraySetAsSeries(Buffer1, true); ArraySetAsSeries(Buffer2, true); //--- initial zero if(prev_calculated < 1) { ArrayInitialize(Buffer1, EMPTY_VALUE); ArrayInitialize(Buffer2, EMPTY_VALUE); } else limit++; if(BarsCalculated(MA_handle) <= 0) return(0); if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total); ArraySetAsSeries(MA, true); if(BarsCalculated(MA_handle2) <= 0) return(0); if(CopyBuffer(MA_handle2, 0, 0, rates_total, MA2) <= 0) return(rates_total); ArraySetAsSeries(MA2, true); if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total); ArraySetAsSeries(Low, true); if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total); ArraySetAsSeries(High, true); //--- main loop for(int i = limit-1; i >= 0; i--) { if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation //Indicator Buffer 1 if(MA[i] > MA2[i] && MA[i+1] < MA2[i+1] //Moving Average crosses above Moving Average ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low } else { Buffer1[i] = EMPTY_VALUE; } //Indicator Buffer 2 if(MA[i] < MA2[i] && MA[i+1] > MA2[i+1] //Moving Average crosses below Moving Average ) { Buffer2[i] = High[i]; //Set indicator value at Candlestick High } else { Buffer2[i] = EMPTY_VALUE; } } return(rates_total); } //copy the code to meta editor to compile it
12.04.24、EURUSDのテスト結果チャートは、M1時間枠で観察される期間の開始を示しています。クロスオーバーは、売りシグナルは赤、買いシグナルは青の矢印でその位置を示します。にもかかわらず、より広い視野で見れば、弱気なD1ローソク足を示す明確な下落トレンドが見て取れます。クロスオーバー指標は、実勢トレンドを無視して両方のシグナルを発しており、重要な問題を提起しています。相反するシグナルは、市場をナビゲートしようとするトレーダーにとって困難なシナリオを生み出します。M1の時間枠は短期的なチャンスの可能性を示唆していますが、D1のローソク足では包括的な下降トレンドが見られるため、上昇の持続性に懸念があります。この記事では、シグナルをD1トレンドに限定することで、この問題に対処します。
図1.2 :制約前のMAクロスオーバー指標のテスト結果
D1ローソク足の結果は弱気で、MAクロスオーバーの条件によって買い矢印と売り矢印の両方が発生しています。多くのシグナルはフェイクまたはトレンドから外れていると判断されますが、これは上位時間枠のトレンド制約を組み込むことによって修正することができます。下の表は、始値から終値までのチャート情報を使用して作成しました。
シグナルの種類 | 単位 |
---|---|
売りシグナル | 29 |
買いシグナル | 28 |
合計 | 57 |
フェイクとオフトレンドシグナル | 41 |
成功のシグナル | 25 |
制約の正当化とその適用
トウモロコシとサトウモロコシが混ざっていると想像してみてください。分別するために、ふるいにかけます。この作業によってトウモロコシの粒が閉じ込められ、サトウモロコシだけがふるい落とされ、コントロールのレベルが示されます。この類推は、現在検討されている「上位時間枠」という制約の概念と一致しています。フィルタとして機能し、特定のシグナルをふるい落とし、一般的なトレンドと調和するものだけを残します。上位時間枠の制約は、ふるいに似て、焦点を絞り込み、市場トレンドの本質的な要素を見極めることを可能にします。ノイズをふるいにかけることで、その根底にある原動力をよりよく把握することができ、情報に基づいた意思決定が容易になります。この戦略的アプローチにより、私たちの金融環境の複雑さを乗り越える能力が高まり、トウモロコシの穀物から分離されたサトウもろこしのように、全体的な方向性に沿った状態を維持し、市場の動きの本質を明らかにすることができます。
D1ローソク足の性質を、先にコーディングしたTrend Constraintの条件として定義します。- 私は、前日の終値が当日の始値と類似していることと、下位時間枠のM1ローソク足の終値を比較することで、現在の市場センチメントを強気か弱気かを定義した。
- コードを調べてみましょう。コードはよく構造化されており、従うのは簡単です。
強気ローソク足の場合
直前のM1ローソク足の終値 ≧ 直前のD1ローソク足の終値
弱気ローソク足の場合
直前のM1ローソク足の終値 ≦ 直前のD1ローソク足の終値
D1ローソク足がトレンドドライバーとして強気であれば、買いシグナルのみを受信し、D1ローソク足が弱気であれば、その逆となります。
このストラテジーと指標のスタイルでは、後者はチャート上で矢印を示さないため、Bid価格とAsk価格や当日の終値といった他の側面を利用するのではなく、D1の始まりと比較するポイントとして下位時間枠の終値を選択しました。 したがって、D1の始まりに関連する下位時間枠の終わりに注目することで、チャート上の望ましい視覚的な手がかりや指標と戦略を効果的に一致させることができます。このアプローチにより、取引判断の明確性と精度が高まり、より合理的で効率的な分析プロセスが実現します。
if(Close[1+barshift_M1[i]] >= Open[1+barshift_D1[i]] //Candlestick Close >= Candlestick Open ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low } else { Buffer1[i] = EMPTY_VALUE; }
上記のコードは、強気のD1ローソク足の状態を表しています。弱気については反対が当てはまります。
- 最後に、制約が移動平均クロスオーバー指標とシームレスに統合された最終的なコードを紹介します。
/Indicator Name: Trend Constraint #property copyright "Clemence Benjamin" #property link "https://mql5.com" #property version "1.00" #property description "A model that seek to produce sell signal when D1 candle is Bearish only and buy signal when it is Bullish" //--- indicator settings #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 #property indicator_type1 DRAW_ARROW #property indicator_width1 5/ #property indicator_color1 0xFFAA00 #property indicator_label1 "Buy" #property indicator_type2 DRAW_ARROW #property indicator_width2 5 #property indicator_color2 0x0000FF #property indicator_label2 "Sell" #define PLOT_MAXIMUM_BARS_BACK 5000 #define OMIT_OLDEST_BARS 50 //--- indicator buffers double Buffer1[]; double Buffer2[]; double myPoint; //initialized in OnInit int MA_handle; double MA[]; int MA_handle2; double MA2[]; double Close[]; double Close2[]; double Low[]; double High[]; void myAlert(string type, string message) { if(type == "print") Print(message); else if(type == "error") { Print(type+" | Trend constraint @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } else if(type == "order") { } else if(type == "modify") { } } // Custom indicator initialization function int OnInit() { SetIndexBuffer(0, Buffer1); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(0, PLOT_ARROW, 241); SetIndexBuffer(1, Buffer2); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(1, PLOT_ARROW, 242); //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; } MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle < 0) { Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle2 = iMA(NULL, PERIOD_CURRENT, 21, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle2 < 0) { Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } return(INIT_SUCCEEDED); } // Custom indicator iteration function int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], const double& high[], const double& low[], const double& close[], const long& tick_volume[], const long& volume[], const int& spread[]) { int limit = rates_total - prev_calculated; //--- counting from 0 to rates_total ArraySetAsSeries(Buffer1, true); ArraySetAsSeries(Buffer2, true); //--- initial zero if(prev_calculated < 1) { ArrayInitialize(Buffer1, EMPTY_VALUE); ArrayInitialize(Buffer2, EMPTY_VALUE); } else limit++; datetime TimeShift[]; if(CopyTime(Symbol(), PERIOD_CURRENT, 0, rates_total, TimeShift) <= 0) return(rates_total); ArraySetAsSeries(TimeShift, true); int barshift_M1[]; ArrayResize(barshift_M1, rates_total); int barshift_D1[]; ArrayResize(barshift_D1, rates_total); for(int i = 0; i < rates_total; i++) { barshift_M1[i] = iBarShift(Symbol(), PERIOD_M1, TimeShift[i]); barshift_D1[i] = iBarShift(Symbol(), PERIOD_D1, TimeShift[i]); } if(BarsCalculated(MA_handle) <= 0) return(0); if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total); ArraySetAsSeries(MA, true); if(BarsCalculated(MA_handle2) <= 0) return(0); if(CopyBuffer(MA_handle2, 0, 0, rates_total, MA2) <= 0) return(rates_total); ArraySetAsSeries(MA2, true); if(CopyClose(Symbol(), PERIOD_M1, 0, rates_total, Close) <= 0) return(rates_total); ArraySetAsSeries(Close, true); if(CopyClose(Symbol(), PERIOD_D1, 0, rates_total, Close2) <= 0) return(rates_total); ArraySetAsSeries(Close2, true); if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total); ArraySetAsSeries(Low, true); if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total); ArraySetAsSeries(High, true); //--- main loop for(int i = limit-1; i >= 0; i--) { if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation if(barshift_M1[i] < 0 || barshift_M1[i] >= rates_total) continue; if(barshift_D1[i] < 0 || barshift_D1[i] >= rates_total) continue; //Indicator Buffer 1 if(MA[i] > MA2[i] && MA[i+1] < MA2[i+1] //Moving Average crosses above Moving Average && Close[1+barshift_M1[i]] >= Close2[1+barshift_D1[i]] //Candlestick Close >= Candlestick Close ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low } else { Buffer1[i] = EMPTY_VALUE; } //Indicator Buffer 2 if(MA[i] < MA2[i] && MA[i+1] > MA2[i+1] //Moving Average crosses below Moving Average && Close[1+barshift_M1[i]] <= Close2[1+barshift_D1[i]] //Candlestick Close <= Candlestick Close ) { Buffer2[i] = High[i]; //Set indicator value at Candlestick High } else { Buffer2[i] = EMPTY_VALUE; } } return(rates_total); }
上記のコードの結果は素晴らしいです。下の画像をご参照ください。
図1.4:Trend Constraint適用後の驚くべき結果
シグナルの種類 | 単位 |
---|---|
売りシグナル | 27 |
買いシグナル | 1 |
合計 | 28 |
偽シグナルとオフトレンドシグナル | 3 |
成功のシグナル | 25 |
上の表から、フィルタとしての「上位時間枠のTrend Constraint」がポジティブな影響を与え、その結果、失敗よりも勝利が多く、EAにとって理想的であることがわかります。前回と今回の結果表を比較すると、成功したシグナルはその値を維持し、偽シグナルはすべて減少していることがわかります。このシグナル精度の向上は、私たちのデータ解析手法にプラスの傾向があることを示しています。アルゴリズムと基準を改良することで、偽シグナルの発生を効果的に最小化し、結果の全体的な信頼性を高めています。今後、この進歩が、より多くの情報に基づいた意思決定と、戦略における成果の向上に寄与することは間違いません。
コードを使用するメリット
より長い時間枠のトレンドに制約を課すことの利点は、市場の方向性をより明確にし、過剰取引の傾向を減らし、取引決定により規律あるアプローチを育成することです。この方法はまた、トレーダーが短期的な変動に巻き込まれるのを避け、長期的なトレンドに戦略を合わせることを可能にする、より広い視野を提供することができます。トレーダーは大局的な視点に立つことで、ノイズを排除し、基本的なトレンドに基づいた、より多くの情報に基づいた意思決定をおこなうことができるようになります。このアプローチは、忍耐と市場力学の深い理解を促し、最終的には、より一貫性のある収益性の高い取引結果につながります。さらに、上位時間枠のトレンドに対する制約は、トレーダーが市場の状況を戦略的に評価した上で、エントリポイントとエグジットポイントの明確なレベルを設定することを可能にし、リスク管理のための貴重なツールとして機能します。
要約すると
- シグナル発生指標の精度向上
- リスク管理の向上
- 収益性の向上
- 仕事の減少
- シグナルの減少
結論
上位時間枠のローソク足は、強気であれ弱気であれ、下位時間枠のトレンドに大きな影響を及ぼし、本質的に相場を操縦します。様々な研究に基づいて、下位時間枠で強気な日足の間に買い、弱気なローソク足の間に売ることを考慮することをお勧めします。個人的には、このような上位時間枠のトレンド制限の概念を統合することは、EAや指標の開発において、持続的な好結果をもたらすために極めて重要であると思われます。次の疑問が生じます。移動平均線というトレンドを定義する道具を捨てるべきなのでしょうか。この概念をより洗練させ、進化させるために、おそらく次の記事でこのことに光を当てることになるでしょう。添付のソースコードファイルはMetaEditorで、Ex5ファイルはMeta trader 5プラットフォームで見ることができます。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/14347





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