English Русский 中文 Español Deutsch Português
preview
Candlestick Trend Constraintモデルの構築(第2回):ネイティブ指標の結合

Candlestick Trend Constraintモデルの構築(第2回):ネイティブ指標の結合

MetaTrader 5トレーディング |
295 2
Clemence Benjamin
Clemence Benjamin

内容

  1. はじめに
  2. 歴史を振り返る
  3. 現行システムの問題点の洗い出し
  4. 次のMQL5プログラムのバージョンアップ
  5. 移動平均を探る
  6. 移動平均をプログラムに組み込む
  7. RSIを探る
  8. RSIの実施
  9. 結果の比較
  10. 結論


はじめに

MetaTrader 5には、トレーダーに市場での分析上の優位性を提供するいくつかの指標が組み込まれています。この記事では、そのうちの2つについて具体的に説明します。移動平均線と相対力指数。移動平均線は一般的に、トレンドの方向性や潜在的な支持線・抵抗線を特定するために使用されます。価格データを平滑化し、1本の流れるような線を作成することで、トレンドを見つけやすくします。一方、相対力指数(RSI)はモメンタムオシレーターであり、値動きの速さと変化を測定します。トレーダーはRSIを使用して市場の買われすぎ、売られすぎの状況を判断し、より多くの情報に基づいた取引判断を下すことができます。この2つの指標を組み合わせることで、トレーダーは市場動向や潜在的なエントリ・エグジットポイントについて貴重な洞察を得ることができます。 

以下は、MetaTrader 5でよく使用される組み込み指標の一部です。

  • 移動平均
  • Bollinger Bands(ボリンジャーバンド)
  • Relative Strength index(相対力指数)
  • MACD(移動平均収束ダイバージェンス)
  • Stochastic Oscillator(ストキャスティックス)
  • Average True Range (ATR)
  • Ichimoku Kinko Hyo(一目均衡表)
  • Fibonacci Retracement(フィボナッチ・リトレースメント)

移動平均線と相対力指数を他のテクニカル分析ツールと併用することで、トレーダーはより包括的な取引戦略を開発することができます。市場の状況を常に監視し、それに応じて戦略を調整することで、トレーダーは常に先手を打ち、有益なチャンスを生かすことができます。取引は予測不可能で変動が激しいため、規律を守り、忍耐強くあることが不可欠です。移動平均線と相対力指数を分析に取り入れることで、トレーダーは意思決定プロセスを強化し、市場で成功する可能性を高めることができます。取引は、マスターするのに時間と練習が必要なスキルであることを忘れないでください。取引能力の学習と向上に継続的に取り組むことが重要です。


歴史を振り返る

少なくとも数千バーのヒストリカルデータで指標のパフォーマンスを評価できるよう、以下のコードを検証してみましょう。ローソク足チャートは、各期間の始値、終値、高値、安値の関係を示すことで、市場のトレンドを見極める上で極めて重要です。過去の値動きを分析することで、トレーダーはトレンドの方向性と強さを判断し、それに応じて取引戦略を調整することができます。ローソク足パターンの履歴は、価格がしばしば一時停止または反転する主要な支持と抵抗のレベルを特定することができます。トレーダーは、過去にこれらの水準で価格がどのように動いたかを研究することで、将来の値動きを予測し、取引の効果的なエントリポイントとエグジットポイントを設定することができます。


トレーダーは、過去のローソク足データを利用して取引戦略をバックテストし、さまざまな市場シナリオにおけるパフォーマンスを測定することができます。過去のデータを使用して取引をテストすることで、トレーダーは戦略の有効性を評価し、取引結果を向上させるために必要な調整をおこなうことができます。本質的に、ローソク足チャートの履歴を掘り下げることは、テクニカル分析の重要な要素であり、トレーダーに市場のトレンド、パターン、行動に関する貴重な洞察を提供し、十分な情報に基づいた有益な取引の選択を導くことができます。 

過去のローソク足のパターンを分析するだけでなく、トレーダーはテクニカル指標を使用することで、市場力学の理解をさらに深めることができます。これらの指標は、トレンドの反転や継続のシグナルを提供するだけでなく、潜在的なエントリポイントやエグジットポイントを特定するのに役立ちます。ローソク足チャートから得られる洞察と指標が生成するシグナルを組み合わせることで、トレーダーはプライスアクションとテクニカル分析の両方を考慮に入れた、より包括的な取引戦略を開発することができます。この総合的なアプローチは、意思決定を改善し、ダイナミックで絶えず変化する金融市場で取引を成功させる可能性を高めることができます。

メインコードの一部として、指標がローソク足チャートのヒストリーの中で、どのくらい後方まで表示されるかを定義しているこの部分を検証してみましょう。

#define PLOT_MAXIMUM_BARS_BACK 10000 //the integer value can be made higher expanding the gap you can visualize in history
#define OMIT_OLDEST_BARS 50


現行システムの問題点の洗い出し

この段階では、Trend Constraint指標がチャートに表示するシグナルを検証します。この制約によってネガティブなシグナルはうまくフィルタリングされたものの、視覚的に非常に小さなスケールでトレンドから外れたシグナルが発生するという問題が残っています。これらのシグナルを排除し、本物のトレンドシグナルに集中することが重要です。これは、MQL5を通じて移動平均やRSIのような組み込みツールを活用する必要性を浮き彫りにしています。以下のセクションでは、これらのツールについてさらに掘り下げていきます。

BOOM500指数オフトレンドシグナル

図1:Trend Constraint v1.00、Boom 500指数

これからのセクションでは、移動平均とRSIがトレンド分析を強化し、意思決定のためにより正確なシグナルを提供するのにどのように役立つかを探ります。これらのツールを分析に取り入れることで、取引戦略の全体的な有効性を向上させ、市場でより良い結果を出すことを目指しています。取引アプローチを最適化するために、これらのツールの機能と利点を深く掘り下げてみましょう。


次のMQL5プログラムのバージョンアップ

MQL5の旅が始まると、各ステージが完了するごとにバージョンが上がります。私たちのプログラムに機能を追加し続けるにつれて、新しいレベルにバージョンアップする必要があります。では、コードの冒頭でその方法を見てみましょう。以下は、Trend Constraintの最初のバージョンです。

///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"

バージョンをアップグレードするには、コードのversionプロパティの数字を変更するだけです。例えば、この記事では、次のTrend Constraintのバージョンは1.01とします。以下は、記事の後半でメインコードにどのように表示されるかを示す、更新されたコードスニペットです。

///Indicator Name: Trend Constraint
#property copyright "Clemence Benjamin"
#property link      "https://mql5.com"
#property version   "1.01"
#property description "A model that seek to produce sell signal when D1 candle is Bearish only and  buy signal when it is Bullish"

すばらしいことです。これがMQL5プログラムのアップグレード方法です。次はバージョン1.02、1.03、1.04......と進めていきます。


移動平均を探る

MAは、市場のトレンドを示す上で極めて重要であり、遅い移動平均線と速い移動平均線で構成されます。この2つのクロスオーバーは、トレンドの継続か反転のどちらかを示します。この記事では、トレンドから外れたシグナルを排除するために、周期400のかなり遅い単純移動平均と比較して、周期7の平滑化移動平均を採用しました。このアプローチにより、短期的な変動やノイズをフィルタリングし、基本的な市場トレンドをより正確に表現することが可能になりました。速い移動平均と遅い移動平均を組み合わせて使用することで、偽のシグナルを最小限に抑えながら、トレンドの大きな変化を識別することができました。この方法は、より幅広い市場の動きをとらえ、十分な情報に基づいた取引の意思決定をおこなうための貴重な洞察を提供する上で効果的であることが証明されました。

移動平均は、常に更新される平均価格を作成することで、価格データを平滑化する、広く使用されているテクニカル分析ツールです。トレーダーがトレンドと潜在的な反転ポイントを特定するのに役立ちます。移動平均の概念は、短期的な変動の影響を軽減し、値動きの長期的なトレンドを強調するために開発されました。

 金融分析における移動平均線の使用は、20世紀半ばのRichard DonchianやGeorge Marechalといった初期のテクニカルアナリストにまで遡ることができます。

単純移動平均(SMA)の計算式は簡単です。

SMA = (P1 + P2 ... + Pn)/n

ここで

  • SMA = 単純移動平均
  • P1,P2,...,Pn = 指定期間の価格(終値など)
  • n = 平均を計算する期間(日数など)の数

EURUSDチャート 移動平均線

図2:移動平均、EURUSD

移動平均をプログラムに組み込む

最も遅い移動平均は、トレンドの変化を特定する上で重要な意味を持ちます。これは、価格が遅い移動平均線とどのように相互作用するかを見れば明らかです。通常、相場は遅行移動平均線を何度も試した後、トレンドが継続または変化します。遅行移動平均線は現在の値動きに密接に追随しています。このように、遅行移動平均線は、基調の強さを反映する強固な支持線または抵抗線として機能します。トレーダーは、トレンドの反転や継続を確認するために、このインディケ ーターをよく使用します。価格と遅行移動平均の関係を観察することで、投資家は市場力学に関する貴重な洞察を得て、十分な情報に基づいた取引判断を下すことができます。

加えて、遅行移動平均の価格変動を滑らかにする能力は、トレーダーに市場全体の方向性をより明確に示すことができます。価格と遅行移動平均の収束または乖離に注目することで、投資家はモメンタムの潜在的な変化を予測することができます。この指標は、長期的なトレンドを捉える信頼性が高いため、短期的なノイズを排除しつつ、大幅な値動きを乗り切ろうとするトレーダーにとって貴重なツールとなります。遅行移動平均のニュアンスを理解することで、トレーダーは複雑な金融市場をより正確かつ確信を持ってナビゲートする能力を高めることができます。

前回の記事では、売りと買いの2つのバッファを持つD1 Trend Constraint指標を開発しました。当初は満足のいくものでありましたが、現在の目標はその効果をさらに高めることです。以前の作品と同様、コードは2つのバッファで構成されています。私たちの目的は、偽のシグナルをフィルタリングするために、出力を遅い移動平均に限定することです。遅行移動平均線はトレンドを判断する上で重要な役割を果たします。この制限では、価格がSMA400より高いときだけ買い、低いときだけ売ることになります。

  1. 価格を表す平滑化単純移動平均(SSMA) 7
  2. トレンドの強制を表す単純移動平均400
  3. MQL5コード
///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 0xD42A00
#property indicator_label1 "Buy"

#property indicator_type2 DRAW_ARROW
#property indicator_width2 5
#property indicator_color2 0x0000D4
#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 Open[];
double Close[];
int MA_handle3;
double MA3[];
int MA_handle4;
double MA4[];
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);
     }
   
   MA_handle3 = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_SMMA, PRICE_CLOSE);
   if(MA_handle3 < 0)
     {
      Print("The creation of iMA has failed: MA_handle3=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle4 = iMA(NULL, PERIOD_CURRENT, 400, 0, MODE_SMA, PRICE_CLOSE);
   if(MA_handle4 < 0)
     {
      Print("The creation of iMA has failed: MA_handle4=", 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(CopyOpen(Symbol(), PERIOD_M1, 0, rates_total, Open) <= 0) return(rates_total);
   ArraySetAsSeries(Open, true);
   if(CopyClose(Symbol(), PERIOD_D1, 0, rates_total, Close) <= 0) return(rates_total);
   ArraySetAsSeries(Close, true);
   if(BarsCalculated(MA_handle3) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle3, 0, 0, rates_total, MA3) <= 0) return(rates_total);
   ArraySetAsSeries(MA3, true);
   if(BarsCalculated(MA_handle4) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle4, 0, 0, rates_total, MA4) <= 0) return(rates_total);
   ArraySetAsSeries(MA4, 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
      && Open[barshift_M1[i]] >= Close[1+barshift_D1[i]] //Candlestick Open >= Candlestick Close
      && MA3[i] > MA4[i] //Moving Average > 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
      && Open[barshift_M1[i]] <= Close[1+barshift_D1[i]] //Candlestick Open <= Candlestick Close
      && MA3[i] < MA4[i] //Moving Average < Moving Average
      )
        {
         Buffer2[i] = High[i]; //Set indicator value at Candlestick High
        }
      else
        {
         Buffer2[i] = EMPTY_VALUE;
        }
     }
   return(rates_total);
  }
//Thank you for following along this is ready to  compile


RSIオシレーターを探る

RSIは、買われすぎや売られすぎなど、市場の極端なゾーンを特定するのに役立ちます。これは、潜在的な反転ポイントやトレンド継続の機会を判断したいトレーダーにとって有用です。RSIを他のテクニカル指標や分析手法と併用することで、トレーダーは取引のエントリやエグジット時に、より多くの情報に基づいた意思決定をおこなうことができます。さらに、RSIはトレンドの強さを確認したり、方向転換の可能性を示す価格とモメンタムのダイバージェンスを発見したりするためにも使用できます。トレーダーは、RSIだけに依存することには慎重であるべきであり、取引の意思決定をおこなう前に、市況、ニュースイベント、全体的な市場センチメントなどの他の要因を常に考慮すべきです。1つの指標が完璧に機能することはなく、取引戦略を成功させるためには、多くの場合、ツールと分析の組み合わせが必要であることを覚えておくことが重要です。

以下のRSIの計算式は、1978年にこの概念を導入したJ.ウェルズ・ワイルダー・ジュニアによるものです。

RSI = 100 - (100/(1+RS))

ここで

  • RS = 平均利得 / 平均損失
  • 平均利益=特定期間の利益の合計/期間数
  • 平均損失=特定期間の損失の合計/期間数

Boom 500指数のRSI

図3:RSIレベル、Boom 500指数

RSIの実施

コードでRSIレベルを特定し、主要トレンドと整合させることは非常に有用です。このセクションでは、RSIの条件をMQL5の指標プログラムに組み込みます。MQL5の指標プログラムにRSIの条件を組み込むことで、市場動向をよりよく分析し、より多くの情報に基づいた取引判断を下すことができるようになります。RSIレベルを主なトレンドに合わせることで、潜在的なエントリポイントとエグジットポイントをより正確に特定することができ、取引戦略の有効性を高めることができます。以前は移動平均線のクロスオーバーをエントリ条件としていました。今は、MAクロスオーバーを削除し、代わりにRSIレベルをエントリに使用し、他の最近組み込まれた条件とともに、新しいバージョンであるTrend Constrain V1.02を作成しています。

 この段階で、買われすぎと売られすぎのゾーンを最適化するために、RSIの値を入力する必要があります。以下のコードを確認してください。

input double Oversold = 30;
input double Overbought = 70;
//I have set the default standard values, but you can alter them to suit your strategy and instrument being traded.

それでは、これらのRSI条件をコードに実装し、指標の機能を強化しましょう。まず、指標で使用するRSIレベルを定義することから始めましょう。買われすぎの水準を70に、売られすぎの水準を30に設定できます。これは、市場の反転ポイントを特定するのに役立ちます。次に、これらのRSI条件を確認し、それに応じてシグナルを生成するために必要なロジックをコードに追加します。そうすることで、市場力学をより包括的に把握することができ、より多くの情報に基づいた取引判断ができるようになります。これらの変更をMQL5指標プログラムに実装してみましょう。

///Indicator Name: Trend Constraint
#property copyright "Clemence Benjamin"
#property link      "https://mql5.com"
#property version   "1.02"
#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 0xFF3C00
#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[];

input double Oversold = 30;
input double Overbought = 70;
double myPoint; //initialized in OnInit
int RSI_handle;
double RSI[];
double Open[];
double Close[];
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 V1.02 @ "+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;
     }
   RSI_handle = iRSI(NULL, PERIOD_CURRENT, 14, PRICE_CLOSE);
   if(RSI_handle < 0)
     {
      Print("The creation of iRSI has failed: RSI_handle=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_SMMA, 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, 400, 0, MODE_SMA, 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(RSI_handle) <= 0) 
      return(0);
   if(CopyBuffer(RSI_handle, 0, 0, rates_total, RSI) <= 0) return(rates_total);
   ArraySetAsSeries(RSI, true);
   if(CopyOpen(Symbol(), PERIOD_M1, 0, rates_total, Open) <= 0) return(rates_total);
   ArraySetAsSeries(Open, true);
   if(CopyClose(Symbol(), PERIOD_D1, 0, rates_total, Close) <= 0) return(rates_total);
   ArraySetAsSeries(Close, true);
   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   
      
      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(RSI[i] < Oversold
      && RSI[i+1] > Oversold //Relative Strength Index crosses below fixed value
      && Open[barshift_M1[i]] >= Close[1+barshift_D1[i]] //Candlestick Open >= Candlestick Close
      && MA[i] > MA2[i] //Moving Average > Moving Average
      )
        {
         Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low
        }
      else
        {
         Buffer1[i] = EMPTY_VALUE;
        }
      //Indicator Buffer 2
      if(RSI[i] > Overbought
      && RSI[i+1] < Overbought //Relative Strength Index crosses above fixed value
      && Open[barshift_M1[i]] <= Close[1+barshift_D1[i]] //Candlestick Open <= Candlestick Close
      && MA[i] < MA2[i] //Moving Average < Moving Average
      )
        {
         Buffer2[i] = High[i]; //Set indicator value at Candlestick High
        }
      else
        {
         Buffer2[i] = EMPTY_VALUE;
        }
     }
   return(rates_total);
  }
// Thank you for following along we are here


結果の比較

前回の記事を見直した結果、提示されたシグナル数で明確なチャートを作成することに大きな進歩がありました。RSIと移動平均は、トレンドの変化を監視する視覚的な指標として、私たちの成績にプラスの効果をもたらしています。より長い時間枠のローソク足Trend Constraint指標も改善を見せています。加えて、SMA400指標を取り入れることで、潜在的な相場の反転に関する洞察がさらに深まり、全体的な分析精度が向上しました。こうしたさまざまなシグナルを組み合わせることで、十分な情報に基づいた取引判断を下し、変化する市場環境に適応することができます。これまでの進歩に胸を躍らせているとともに、今後さらに良い結果を出すために、この戦略に磨きをかけていくことをお約束します。

Boom 500指数、スマートチャート

図4:Trend Constraint v1.02、Boom 500指数

上の画像は、記事の冒頭で現行システムの問題点を洗い出したときのものです。

Boom 500指数Trend Constraint v1.02

図5:Trend Constraint v1.02、Boom 500指数


結論

Candlestick Trend Constraint指標は移動平均線に取って代わることはできませんが、優れた結果を得るために移動平均線を補完することができます。MT5の組み込み指標は、他のカスタム指標を作成するための基礎となります。これらのツールを併用すれば、非常に効果的です。私たちはこの開発において新たな段階に進み、注意を要する重みや更新の課題に直面し始めています。次回は、このシステムの改良を続けながら、これらの課題に取り組むことに集中します。

Algobookをを参照


MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/14803

最後のコメント | ディスカッションに移動 (2)
Takudzwa Matumba
Takudzwa Matumba | 19 5月 2024 において 00:23
深い!
Clemence Benjamin
Clemence Benjamin | 20 5月 2024 において 08:19
Taque Matumbah #:
深い!

ありがとう。お役に立てたなら幸いです。

ニューラルネットワークが簡単に(第69回):密度に基づく行動方策の支持制約(SPOT) ニューラルネットワークが簡単に(第69回):密度に基づく行動方策の支持制約(SPOT)
オフライン学習では、固定されたデータセットを使用するため、環境の多様性をカバーする範囲が制限されます。学習過程において、私たちのエージェントはこのデータセットを超える行動を生成することができます。環境からのフィードバックがなければ、そのような行動の評価が正しいとどうやって確信できるのでしょうか。訓練データセット内のエージェントの方策を維持することは、訓練の信頼性を確保するために重要な要素となります。これが、この記事でお話しする内容です。
カスタム指標(第1回):MQL5でシンプルなカスタム指標を開発するためのステップバイステップ入門ガイド カスタム指標(第1回):MQL5でシンプルなカスタム指標を開発するためのステップバイステップ入門ガイド
MQL5を使用してカスタム指標を作成する方法を紹介します。この入門記事では、シンプルなカスタム指標を構築するための基本を説明し、この興味深いトピックを初めて学ぶMQL5プログラマーのために、さまざまなカスタム指標をコーディングするための実践的なアプローチを示します。
初心者からプロまでMQL5をマスターする(第2回):基本的なデータ型と変数の使用 初心者からプロまでMQL5をマスターする(第2回):基本的なデータ型と変数の使用
初心者向け連載の続きです。この記事では、定数や変数を作成する方法、日付や色、その他の便利なデータを書き込む方法を見ていきます。曜日や線のスタイル(実線、点線など)を列挙する方法も学びます。変数と式はプログラミングの基本です。これらは99%のプログラムに間違いなく存在するので、理解することは非常に重要です。したがって、この記事はとてもプログラミング初心者の役に立つでしょう。必要なプログラミング知識レベル:前回の記事(冒頭のリンク参照)の範囲内で、ごく基本的なものです。
知っておくべきMQL5ウィザードのテクニック(第17回):多通貨取引 知っておくべきMQL5ウィザードのテクニック(第17回):多通貨取引
ウィザードを介してEAが組み立てられた場合、デフォルトでは複数の通貨をまたいだ取引は利用できません。トレーダーが一度に複数の銘柄から自分のアイデアをテストする際に、2つの可能なトリックを検討します。