English Deutsch
preview
MQL5入門(第12回):初心者のためのカスタムインジケーター作成ガイド

MQL5入門(第12回):初心者のためのカスタムインジケーター作成ガイド

MetaTrader 5トレーディング | 16 6月 2025, 14:37
92 2
Israel Pelumi Abioye
Israel Pelumi Abioye

はじめに

MQL5の連載にようこそ。これまで、組み込みインジケーターの操作、エキスパートアドバイザー(EA)の作成、MQL5の基本概念の探求、そして実践的なプロジェクトを通じた知識の応用など、さまざまな内容を扱ってきました。今回は、一からカスタムインジケーターを作成する方法を学び、さらに一歩前進しましょう。インジケーターが内部でどのように動作しているかを深く理解することで、組み込み機能に頼ることなく、その動作やデザインを完全にコントロールできるようになります。MQL5に組み込まれている移動平均やMACDが、どのように作られているのか疑問に思ったことはありませんか。iRSIやiMAなどの関数が存在しなかったとしても、インジケーターを構築することは可能なのでしょうか。 

このプロジェクトベースのアプローチでは、プロセスを2つの主要なステップに分けて進めます。まず、iMA関数を一切使わずに、移動平均インジケーターを完全にゼロから構築します。次に、従来のライン表示だった移動平均をローソク足のようなスタイルに変換し、さらなる発展を加えます。この実践的な手法を通じて、自分のニーズに特化した取引ツールを開発するための新たな可能性が広がることでしょう。

ライン形式の移動平均

図1:MAライン形式

ローソク足形式の移動平均

図2:MAローソク足形式

この記事では、次の内容を学びます。

  • MQL5でカスタムインジケーターをゼロから作成する方法
  • ライン形式とローソク足形式でインジケーターを描画する違い
  • 計算した値を保存・表示するためのインジケーターバッファの使い方
  • インジケーターのプロパティを正しく設定する方法
  • MQL5でカスタム移動平均インジケーターを作成する手順
  • SetIndexBuffer()を使ってインジケーターバッファをマッピングする方法
  • OnCalculate()関数を使って価格データを処理する方法
  • 価格変動に基づいてローソク足の色を判定する方法

MQL5が初めての方でも安心して学べるように、この記事は初心者向けに構成されています。コードの各行について丁寧に解説し、複雑な概念も一歩ずつ理解できるように分解して説明します。チュートリアルを終える頃には、MQL5におけるカスタムインジケーターの仕組みについてしっかりと理解できているはずです。実践的で、わかりやすい内容を心がけています。


1. カスタムインジケーター

1.1. カスタムインジケーターとは

カスタムインジケーターとは、MQL5において標準では提供されていないインジケーターのことです。MetaTrader 5に搭載されている移動平均(MA)、相対力指数(RSI)やMACDなどの組み込みインジケーターとは異なり、ユーザー自身が独自のインジケーターを作成して、特定の計算をおこなったり、シグナルを出したり、市場データを任意の形式で表示することができます。

iMA()、iRSI()、iMACD()などの関数を使えば、組み込みインジケーターを取引戦略に簡単に組み込むことができます。しかし、これらにはカスタマイズの制限があります。一方、カスタムインジケーターであれば、計算ロジックや表示方法を完全に自分で制御できるため、特定の取引スタイルやニーズに合わせたツールを作成することが可能です。組み込みインジケーターでは対応できないような独自の手法で市場を分析したいトレーダーにとって、カスタムインジケーターは非常に有用です。MQL5によるプログラミングを活用することで、価格の動きやトレンド、潜在的な取引チャンスをより深く理解できる独自のインジケーターを設計することができます。

比喩的な説明

リビングルームに本棚を置く場面を想像してみてください。組み込みインジケーターは、あらかじめ組み立てられた本棚を販売している店のようなものです。これらの本棚は決まったサイズや形状、機能を備えており、標準的なデザインとして提供されています。多くの人にとっては、手軽で便利で、十分に機能します。しかし、部屋の形が特殊だったり、珍しいサイズの本を収納したい場合には、既製品の本棚ではうまく収まらなかったり、ニーズを満たせないことがあります。

一方、カスタムインジケーターは、自分で作る本棚のようなものです。寸法、棚の数、素材を自分で選び、空間にぴったり合い、本を好みに合わせて整理できるように設計できます。同様に、取引においても、カスタムインジケーターを使えば、組み込みインジケーターでは得られない柔軟性と精度を手に入れることができ、自分の戦略に最適化されたソリューションを実現できます。

1.2. EAとインジケーターの違い

インジケーターとEAは、いずれも市場データを評価する点では似ていますが、その役割は大きく異なります。EAは、取引を自動化するために設計されており、相場の分析に加えて、あらかじめ定めたルールに従って実際に取引を実行する機能を持っています。具体的には、リスク管理、ストップロスの調整、テイクプロフィットレベルの設定、注文の発注や決済などをおこなうことが可能です。EAにおいて最も重要な関数の1つであるOnTick()は、新しい価格情報が届くたびに呼び出されます。この関数を通じて、EAはリアルタイムで価格の変動を監視し、取引条件が満たされているかを判断してから、注文を実行します。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

//

  }

対照的に、インジケーターには取引を実行する力はありません。インジケーターは、あくまで市場分析に特化しており、実際の取引はおこないません。EAがOnTick()を使用するのに対し、インジケーターではOnCalculate()という関数が使用されます。これは、過去および現在のデータを分析して、取引の参考となるシグナルを生成するための関数です。インジケーターの役割は、インジケーター値の計算、チャート要素の更新、トレンドラインや色付きローソク足といった視覚的なシグナルの表示などを含みます。これらの処理はすべてOnCalculate()によって実行されます。

インジケーターはあくまで有益な情報を提供するだけで、最終的な判断はトレーダーに委ねられます。一方でEAは、取引チャンスに対して自動的に行動するように設計されたツールです。どちらも市場データを分析する点では共通していますが、目的は異なります。インジケーターは、トレーダーが自ら市場を読み取り、より適切な意思決定をおこなうことをサポートするものであり、EAはその判断と実行を自動化する存在です。

//+------------------------------------------------------------------+
//| 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[])
  {
//
  }

比喩的な説明

インジケーターとEAは、まったく異なる2種類の取引ツールと考えることができます。EAは、まるで自動運転車のように、市場を分析し、判断を下し、取引を自動で実行します。人間の操作なしに、取引手法を適用し、市場の変動を継続的に監視し、リスク管理もおこないます。

一方で、インジケーターはどちらかというとカーナビのような存在です。進むべき方向は示してくれますが、実際に何かを行動に移すわけではありません。市場データを分析し、パターンを特定し、価格変動を理解する手助けをしてくれます。たとえば移動平均線は、市場が上昇傾向にあるのか下降傾向にあるのかを示すことができますが、自ら取引を開始したり終了したりすることはできません。インジケーターは情報を提供するだけで、最終的な判断と行動はトレーダー次第です。一方、EAはトレーダーに代わって実際に取引をおこなうツールです。


2. プロジェクトの設定

カスタムインジケーターとは何か、そしてそれがEAや組み込みインジケーターとどのように異なるかを理解したところで、次はMQL5でインジケーターを作成・修正する方法を見ていきましょう。このセクションでは、インジケーターを最初から作成する手順を詳しく解説し、しっかりと理解できるようにします。既存のインジケーターのルーチン(たとえばMA)を使わず、今回のチュートリアルでは完全にオリジナルの2つのインジケーターをゼロから構築します。

2.1. Line MA

最初に作成するインジケーターは、シンプルな移動平均インジケーターです。これは、以下の3種類の異なる移動平均を計算し、チャート上に表示します。

  • 高値を基準とした200期間の移動平均
  • 終値を基準とした100期間の移動平均
  • 始値を基準とした50期間の移動平均

カスタムインジケーターを構築するには、まずその動作のロジックを正確に理解することが重要です。コードを書く前に、インジケーターがどのように市場データを処理し、どのような情報を表示するのかを明確に定義しておく必要があります。このステップによって、設計に一貫性が生まれ、実装もスムーズになります。ロジックを把握するだけでなく、疑似コードを作成することも重要なステップです。疑似コードを使うことで、実装をより細かく、管理しやすい単位に分割できます。何をすべきかを明確にすることで、エラーの発生を抑え、コーディングの効率を高めることができます。

このセクションでは、異なる価格ソースを使って3本の移動平均を計算・表示するためのロジックについてまず確認し、それに基づいた疑似コードを作成してから、実際のコードの実装へと進みます。このように構造化されたアプローチにより、明確な設計に基づいたカスタムインジケーターを作成でき、MQL5の基本的なプログラミング概念をより深く理解することにもつながります。

擬似コード

// インジケーターをセットアップする

1. チャートウィンドウに表示するインジケーターを設定します。

2. 移動平均(MA200、MA100、MA50)のデータを格納するための3つのバッファを定義します。

3. チャート上に移動平均を表示するための3つのプロットを定義します。

// プロットプロパティの設定

4. MA200の場合

  • ラベル:「MA200」
  • 型:ライン
  • スタイル:ダッシュ・ドット・ドット
  • 幅:1
  • 色:青

5. MA100の場合

  • ラベル:「MA100」
  • 型:ライン
  • スタイル:ダッシュ
  • 幅:1
  • 色:茶色

6. MA50の場合

  • ラベル:「MA50」
  • 型:ライン
  • スタイル:ドット
  • 幅:1
  • 色:紫

// バッファを定義する

7. 計算された値を格納するバッファを作成します。

  • MA200
  • MA100
  • MA50

// 入力パラメータを定義する

8. ユーザーが各移動平均の期間を設定できるようにします。

  • MA200:デフォルト期間 = 200
  • MA100:デフォルト期間 = 100
  • MA50:デフォルト期間 = 50

// 初期化関数

9. インジケーターが初期化されたら、次をおこないます。

  • 各バッファを対応するプロットに割り当てる
  • 各移動平均に対してスキップする初期バーの数を設定する
  • MA200:最初の200バーをスキップ
  • MA100:最初の100バーをスキップ
  • MA50:最初の50バーをスキップ

// 計算関数

10. 新しいローソク足ごとに、またはチャートが更新されるたびに

直近の200本、100本、50本のバーの高値、終値、始値をそれぞれ合計し、対応する期間で割った結果を各バーごとに計算し、それを適切なバッファに格納してMA200、MA100、MA50を算出します。

2.2. Candle MA

次に、ローソク足形式で価格のトレンドを表す異なる移動平均インジケーターを作成します。このインジケーターは期間5の移動平均を使用し、ラインではなくローソク足を使ってその値を視覚的に表現します。移動平均データをこのように表示することで、短期的なトレンドを強調し、市場のノイズをより効果的にフィルタリングできます。これにより、移動平均の計算原理を保ちつつ、価格変動に対する独自の視点を提供します。

すべてのプロジェクトを丁寧に解説し、コードの一行一行が初心者にも理解しやすいように説明します。このパートを終える頃には、ゼロからインジケーターを作成・修正する実践的な経験が身につき、今後のプロジェクトに役立つスキルが得られます。

擬似コード

// インジケーターをセットアップする

1. インジケーターを別のウィンドウに表示するように設定します。

2. 以下を格納する5つの配列(バッファ)を作成します。

  • 始値(OpenBuffer)
  • 高値(HighBuffer)
  • 安値(LowBuffer)
  • 終値(CloseBuffer)
  • ローソクの色(ColorBuffer:0 = 緑、1 = 赤)

3. ローソク足を表示するためのプロットを1つ定義します。

// プロットプロパティの設定

4. プロットについて:

  • ラベル:「Candles」
  • 型:色付きローソク足(DRAW_COLOR_CANDLES)
  • 色:緑は強気、赤は弱気
  • スタイル:塗りつぶし
  • 幅:1

// 入力パラメータを定義する

5. ユーザーが平滑化期間を設定できるようにします(デフォルト = 5)。

// 初期化関数

6. インジケーターが初期化されたら、次をおこないます。

  • 各バッファを対応するデータまたはカラーインデックスに割り当てます。
  • スキップする初期バーの数を設定します(平滑化期間に等しい)。

// 計算関数

7. 新しいローソク足ごとに、またはチャートが更新されるたびに

  • 計算するのに十分なバー(少なくとも「period」バー)があるかどうかを確認します。
  • そうでない場合は、エラーメッセージを出力して停止します。

8. 「period-1」バーから最新バーまでの各バーについて

平滑化された始値、高値、安値、終値を計算します。

  • 最後の「period」バーの始値、高値、安値、終値を合計する
  • 各合計を「period」で割って平均を算出する
  • 結果をOpenBuffer、HighBuffer、LowBuffer、CloseBufferに格納する

ローソク足の色を設定します。

  • 平滑化された終値 >= 平滑化された始値の場合、色を緑(0)に設定する
  • それ以外の場合は、色を赤(1)に設定する


3. カスタムインジケーターの作成とカスタマイズ

すでに擬似コードを作成しているため、これからカスタムインジケーターの作成と修正をおこなうことができます。明確な戦略が定まっていれば、そのロジックを段階的に実装していくことで、インジケーターが意図通りに動作するか確認しながら進めることができます。コードを適切に構成することで、市場の動きを効果的に視覚化し、自分のニーズに合わせてインジケーターを調整することが可能になります。

3.1.ライン形式での移動平均インジケーターの構築

インジケーターを作成する際の最初のステップは、その見た目や動作をイメージすることです。コードを書く前に、設計と実装を理解するためにいくつかの重要な質問を自分自身に投げかけることが大切です。

  • インジケーターはメインチャートウィンドウに表示するか、それとも別ウィンドウに表示するか
  • データを保存・表示するために、いくつのバッファが必要か
  • 表示形式はラインか、ヒストグラムか、ローソク足か、あるいは他の形式か
  • 各要素にはどんな色を割り当てると視認性が高くなるか
  • インジケーターは複数の価格データ(高値、安値、始値、終値など)を使用するか

これらの質問に答えることで、インジケーターの設計図が明確になり、開発プロセスがよりスムーズかつ体系的に進められます。

//INDICATOR IN CHART WINDOW
#property indicator_chart_window

//SET INDICATOR BUFFER TO STORE DATA
#property indicator_buffers 3

//SET NUMBER FOR INDICATOR PLOTS
#property indicator_plots   3

解説

チャートウィンドウのインジケーター
#property indicator_chart_window

カスタムインジケーターを別ウィンドウに表示するのではなく、このディレクティブはMetaTrader 5に、価格の動きを表示するメインチャート上に直接インジケーターを表示するよう指示します。RSIやMACDのようにインジケーターを別ウィンドウにプロットしたい場合は、次のように指定します。

#property indicator_separate_window

このディレクティブは、インジケーターが価格チャート上に直接プロットされるのではなく、メインチャートの下にある別ウィンドウに表示されることを保証します。

データを格納するためのインジケーターバッファの設定

#property indicator_buffers 3

チャート上にプロットされる計算済みの値は、「インジケーターバッファ」と呼ばれる配列に格納されます。インジケーターのそれぞれの要素は、個別のバッファによって表されます。この例では、3種類の異なる値を保持するために3つのインジケーターバッファを作成します。なぜなら、期間の異なる3種類の移動平均(50、100、200)を構築しており、それぞれの移動平均の値を独立して保持するために3つのバッファが必要だからです。

インジケータープロットの数の設定

#property indicator_plots   3

これは、インジケーターがいくつのプロットを表示するかを指定します。プロットとは、チャート上に表示される個別のグラフィカルな表現のことです。今回の場合、50・100・200期間の移動平均をそれぞれ描画するため、3つのプロットが必要になります。

各プロットは、色・スタイル・表示形式(ライン、ヒストグラム、ローソク足など)を個別にカスタマイズすることが可能です。ここでは、それぞれの移動平均をライン形式で表示し、3本の異なる移動平均線として視覚的に表現します。

まとめ

  • インジケーターはメインチャートに表示される:#property indicator_chart_window
  • 3つの値セットをインジケーターバッファに格納する:#property indicator_buffers 3
  • 3本の異なる移動平均線を描画する:#property indicator_plots 3

この設定により、インジケーターが3つの移動平均を正しく計算し、価格チャートに表示できるようになります。

図3:プロットとウィンドウチャート

インジケーターの基本的な特性を定義した後は、プロットのプロパティを設定する段階に入ります。MQL5でカスタムインジケーターを作成する際に、チャート上でインジケーターがどのように表示されるかを指定するためには、プロット属性を設定することが重要です。描画の種類、ラインのスタイル、太さ、色、ラベルなどは、すべてこれらのパラメータで決定されます。こうしたパラメータを理解することで、さまざまな用途に応じたインジケーターの作成・カスタマイズができるようになります。本記事ではプロジェクトベースのアプローチでカスタムインジケーターの設計方法を学ぶことを目的としているため、これらの要素を正しく把握することは非常に有益です。

//INDICATOR IN CHART WINDOW
#property indicator_chart_window

//SET INDICATOR BUFFER TO STORE DATA
#property indicator_buffers 3

//SET NUMBER FOR INDICATOR PLOTS
#property indicator_plots   3

//SETTING PLOTS PROPERTIES
//PROPERTIES OF THE FIRST MA (MA200)
#property indicator_label1  "MA 200"    //GIVE PLOT ONE A NAME
#property indicator_type1   DRAW_LINE  //TYPE OF PLOT THE FIRST MA 
#property indicator_style1  STYLE_DASHDOTDOT  //STYLE OF SPOT THE FIRST MA
#property indicator_width1  1         //LINE THICKNESS THE FIRST MA
#property indicator_color1  clrBlue    //LINE COLOR THE FIRST MA

//PROPERTIES OF THE SECOND MA (MA100)
#property indicator_label2  "MA 100"   //GIVE PLOT TWO A NAME
#property indicator_type2   DRAW_LINE  //TYPE OF PLOT THE SECOND MA
#property indicator_style2  STYLE_DASH  //STYLE OF SPOT THE SECOND MA
#property indicator_width2  1          //LINE THICKNESS THE SECOND MA
#property indicator_color2  clrBrown    //LINE COLOR THE SECOND MA

//PROPERTIES OF THE THIRD MA (MA50)
#property indicator_label3  "MA 50"    //GIVE PLOT TWO A NAME
#property indicator_type3   DRAW_LINE  //TYPE OF PLOT THE THIRD MA
#property indicator_style3  STYLE_DOT  //STYLE OF SPOT THE THIRD MA
#property indicator_width3  1          //LINE THICKNESS THE THIRD MA
#property indicator_color3  clrPurple    //LINE COLOR THE THIRD MA

解説

1番目の移動平均線(MA 200)

#property indicator_label1  "MA 200"    //GIVE PLOT ONE A NAME
#property indicator_type1   DRAW_LINE  //TYPE OF PLOT THE FIRST MA 
#property indicator_style1  STYLE_DASHDOTDOT  //STYLE OF SPOT THE FIRST MA
#property indicator_width1  1         //LINE THICKNESS THE FIRST MA
#property indicator_color1  clrBlue    //LINE COLOR THE FIRST MA

1番目の移動平均(MA 200)は、太さ1の青い破線として表示されます。

2番目の移動平均線(MA 100)

#property indicator_label2  "MA 100"   //GIVE PLOT TWO A NAME
#property indicator_type2   DRAW_LINE  //TYPE OF PLOT THE SECOND MA
#property indicator_style2  STYLE_DASH  //STYLE OF SPOT THE SECOND MA
#property indicator_width2  1          //LINE THICKNESS THE SECOND MA
#property indicator_color2  clrBrown    //LINE COLOR THE SECOND MA

2番目の移動平均線(MA 100)は、太さ1の茶色の破線として表示されます。

3番目の移動平均線(MA 50)

#property indicator_label3  "MA 50"    //GIVE PLOT TWO A NAME
#property indicator_type3   DRAW_LINE  //TYPE OF PLOT THE THIRD MA
#property indicator_style3  STYLE_DOT  //STYLE OF SPOT THE THIRD MA
#property indicator_width3  1          //LINE THICKNESS THE THIRD MA
#property indicator_color3  clrPurple    //LINE COLOR THE THIRD MA

3番目の移動平均線(MA 50)は、太さ1の紫色の点線として表示されます。

MQL5のプロットプロパティの関係を理解する

インジケーターをチャート上にどのように表示するかを決定する際、各プロット(ライン、ヒストグラム、矢印など)には、それぞれの外観を制御するための特性セットが必要です。MQL5では、indicator_label1、indicator_type1、indicator_style1などのように番号付きの接尾辞を使って、それぞれのプロットにプロパティを割り当てます。

この番号付けにより、各プロットに関連するプロパティが確実にグループ化される仕組みになっています。詳しく見てみましょう。

  • indicator_label1:最初のプロットの名前を設定し、インジケーター上で識別しやすくする
  • indicator_type1:最初のプロットがどのように描画されるかを指定する(例:ライン、ヒストグラムなど)
  • indicator_style1:最初のプロットの線のスタイル(実線、破線、点線など)を決定する
  • indicator_width1:最初のプロットの線の太さを制御する
  • indicator_color1:最初のプロットの色を設定する

関係を明確にする例

これらのプロパティは、それぞれの移動平均線に対応したセットとして考えると分かりやすいです。

プロパティ設定の対象
最初のMA(200)
2番目のMA(100)3番目のMA(50)
indicator_labelX
MAの名前
「MA200」
「MA100」
「MA50」
indicator_typeX
プロットタイプ
DRAW_LINE
DRAW_LINE
DRAW_LINE
indicator_styleX
線のスタイル
STYLE_DASHDOTDOT
STYLE_DASH
STYLE_DOT
indicator_widthX厚さ111
indicator_colorX
color
clrBlue
clrBrown
clrPurple

このアプローチにより、すべてのプロパティが対応する移動平均に正しく割り当てられることが保証され、複数のプロットを整理された方法で指定できるようになります。たとえば、indicator_style2を変更した場合に影響を受けるのは2本目の移動平均線(MA100)だけであり、indicator_color3を変更すれば3本目の移動平均線(MA50)の色だけが変更されます。このように、プロパティの一貫性と整理を保つことで、各移動平均の外観を混乱なく制御することができます。

今回の移動平均インジケーターで使ったプロットタイプ、線のスタイル、色などの基本的なカスタマイズに加えて、MQL5ではさらに多くの表示オプションが用意されています。開発者はこれらの設定を活用して、シンプルなラインだけでなく、バンド、矢印、ヒストグラムなどのより複雑で視覚的なインジケーターを設計することが可能です。変数の種類が多いため、この記事ではすべてを網羅することはせず、1つのインジケーターに絞ったプロジェクトベースのアプローチを採用しています。その中で、他のカスタムインジケーターにも応用できる基本的な考え方や重要なポイントを紹介しています。とはいえ、MQL5にはさらに多くのオプションが存在していることも、知っておくと役立つでしょう。

一般的に、本記事で紹介したロジックは、他のプロットスタイルを分析・構築する際にも応用可能です。しかし、これはすべてのプロットタイプに当てはまるわけではありません。たとえばDRAW_LINEは、1本のバッファだけでプロットが可能ですが、DRAW_CANDLESは、1本のローソク足を描画するのに4つのバッファが必要になります。利用可能なさまざまなプロットの種類とその特定のニーズに関する包括的な説明については、MQL5ドキュメントを参照してください。

プロット属性を設定した後は、インジケーターの計算結果を保持するためのdouble型変数(バッファ)を宣言します。これらのバッファは、チャートに表示される計算済みの値を格納するために不可欠です。変数を宣言した後には、MQL5の関数SetIndexBuffer()を使って、それらの変数をインジケーターバッファに接続する必要があります。このステップによって、各バッファに格納された値が、指定されたプロットに正確に割り当てられ、チャートに正しく表示されることが保証されます。

//INDICATOR IN CHART WINDOW
#property indicator_chart_window

//SET INDICATOR BUFFER TO STORE DATA
#property indicator_buffers 3

//SET NUMBER FOR INDICATOR PLOTS
#property indicator_plots   3

//SETTING PLOTS PROPERTIES
//PROPERTIES OF THE FIRST MA (MA200)
#property indicator_label1  "MA 200"   //GIVE PLOT ONE A NAME
#property indicator_type1   DRAW_LINE  //TYPE OF PLOT THE FIRST MA 
#property indicator_style1  STYLE_DASHDOTDOT  //STYLE OF SPOT THE FIRST MA
#property indicator_width1  1         //LINE THICKNESS THE FIRST MA
#property indicator_color1  clrBlue    //LINE COLOR THE FIRST MA

//PROPERTIES OF THE SECOND MA (MA100)
#property indicator_label2  "MA 100"   //GIVE PLOT TWO A NAME
#property indicator_type2   DRAW_LINE  //TYPE OF PLOT THE SECOND MA
#property indicator_style2  STYLE_DASH  //STYLE OF SPOT THE SECOND MA
#property indicator_width2  1          //LINE THICKNESS THE SECOND MA
#property indicator_color2  clrBrown    //LINE COLOR THE SECOND MA

//PROPERTIES OF THE THIRD MA (MA50)
#property indicator_label3  "MA 50"    //GIVE PLOT TWO A NAME
#property indicator_type3   DRAW_LINE  //TYPE OF PLOT THE THIRD MA
#property indicator_style3  STYLE_DOT  //STYLE OF SPOT THE THIRD MA
#property indicator_width3  1          //LINE THICKNESS THE THIRD MA
#property indicator_color3  clrPurple    //LINE COLOR THE THIRD MA

//SET MA BUFFER TO STORE DATA
double buffer_mA200[];  //BUFFER FOR THE FIRST MA
double buffer_mA100[];  //BUFFER FOR THE SECOND MA
double buffer_mA50[];   //BUFFER FOR THE THIRD MA

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {

//SETTING BUFFER
   SetIndexBuffer(0, buffer_mA200, INDICATOR_DATA);  //INDEX 0 FOR MA200
   SetIndexBuffer(1, buffer_mA100, INDICATOR_DATA);  //INDEX 1 FOR MA100
   SetIndexBuffer(2, buffer_mA50, INDICATOR_DATA);   //INDEX 1 FOR MA50

//---
   return(INIT_SUCCEEDED);
  }

解説

//SET MA BUFFER TO STORE DATA
double buffer_mA200[];  //BUFFER FOR THE FIRST MA
double buffer_mA100[];  //BUFFER FOR THE SECOND MA
double buffer_mA50[];   //BUFFER FOR THE THIRD MA

これらの配列(buffer_mA200、buffer_mA100、buffer_mA50)は、それぞれの移動平均(MA)の計算結果を格納するためのストレージとして機能します。

各バッファは、特定の移動平均に対応しています。

  • buffer_mA200:MA 200の値を格納
  • buffer_mA100:MA 100の値を格納
  • buffer_mA50:MA 50の値を格納

インジケーターがチャート上に表示されるとき、これらのバッファに保持された値がプロットされます。 MQL5でインジケーターの計算値を保存・表示するには、インジケーターバッファの使用が必須です。バッファがなければ、計算結果を保存したり、チャートに表示したりすることはできません。

//SETTING BUFFER
SetIndexBuffer(0, buffer_mA200, INDICATOR_DATA);  //INDEX 0 FOR MA200
SetIndexBuffer(1, buffer_mA100, INDICATOR_DATA);  //INDEX 1 FOR MA100
SetIndexBuffer(2, buffer_mA50, INDICATOR_DATA);   //INDEX 2 FOR MA50

SetIndexBuffer()は、各バッファをインジケーターのプロットシステムにリンクするための関数です。

この関数は3つの引数を取ります。

  • バッファインデックス:使用されるバッファの順番を指定する(0から開始)
  • バッファ変数:指定されたインデックスの値を格納するバッファ
  • バッファの種類:INDICATOR_DATAを指定すると、そのバッファがインジケーターの計算結果を保持することを意味する

各行の内訳

  • SetIndexBuffer(0, buffer_mA200, INDICATOR_DATA);:buffer_mA200をインデックス0(最初のMA)に割り当てる
  • SetIndexBuffer(1, buffer_mA100, INDICATOR_DATA);:buffer_mA100をインデックス1(2番目のMA)に割り当てる
  • SetIndexBuffer(2, buffer_mA50, INDICATOR_DATA);:buffer_mA50をインデックス2(3番目のMA)に割り当てる

この手順をおこなうことで、MQL5のインジケーターシステムは各バッファを正しく認識し、プロットできるようになります。この設定をおこなわないと、インジケーターは正しく動作しません。

インジケーターを作成する上で、その指標の数学的根拠や仕組みをしっかり理解することは非常に重要です。インジケーターが価格変動を正確かつ論理的に評価できてこそ、それは有用な指標といえます。MQL5でインジケーターを実践する前に、インジケーターがどのように機能し、効率的に計算するにはどのような入力が必要かを理解する必要があります。

例として、移動平均を見てみましょう。

移動平均は、価格の変動を平均化することで、短期的なノイズに左右されずにトレンドを視認しやすくする手法です。

移動平均を計算するには、以下のような要素を考慮する必要があります。

期間

移動平均(MA)を計算するために使用される過去のローソク足の本数は、設定された時間枠に依存します。たとえば、200期間の移動平均では、直近の200本のローソク足のデータを平均してラインを描きます。期間が短いほど、移動平均線は直近の価格変動に対して敏感に反応します。一方で、期間が長くなると、価格の変動に対する反応は遅くなりますが、より滑らかな線になります。

価格タイプ

移動平均は、さまざまな価格データを用いて計算することができます。以下は主な価格タイプです。

  • 終値:各ローソク足の終値を使用
  • 始値:各ローソク足の始値を使用
  • 高値:各ローソク足の高値を使用
  • 安値:各ローソク足の安値を使用

本プロジェクトでは、以下の3種類の移動平均を使用します。

  • MA 200:高値に基づいて計算
  • MA 100:終値に基づいて計算
  • MA 50:始値に基づいて計算

これらの基本的な概念を理解することで、MQL5の組み込み関数(例:iMA())を使わずに、移動平均を正しく計算・可視化できるようになります。

//INDICATOR IN CHART WINDOW
#property indicator_chart_window

//SET INDICATOR BUFFER TO STORE DATA
#property indicator_buffers 3

//SET NUMBER FOR INDICATOR PLOTS
#property indicator_plots   3

//SETTING PLOTS PROPERTIES
//PROPERTIES OF THE FIRST MA (MA200)
#property indicator_label1  "MA 200"   //GIVE PLOT ONE A NAME
#property indicator_type1   DRAW_LINE  //TYPE OF PLOT THE FIRST MA 
#property indicator_style1  STYLE_DASHDOTDOT  //STYLE OF SPOT THE FIRST MA
#property indicator_width1  1         //LINE THICKNESS THE FIRST MA
#property indicator_color1  clrBlue    //LINE COLOR THE FIRST MA

//PROPERTIES OF THE SECOND MA (MA100)
#property indicator_label2  "MA 100"   //GIVE PLOT TWO A NAME
#property indicator_type2   DRAW_LINE  //TYPE OF PLOT THE SECOND MA
#property indicator_style2  STYLE_DASH  //STYLE OF SPOT THE SECOND MA
#property indicator_width2  1          //LINE THICKNESS THE SECOND MA
#property indicator_color2  clrBrown    //LINE COLOR THE SECOND MA

//PROPERTIES OF THE THIRD MA (MA50)
#property indicator_label3  "MA 50"    //GIVE PLOT TWO A NAME
#property indicator_type3   DRAW_LINE  //TYPE OF PLOT THE THIRD MA
#property indicator_style3  STYLE_DOT  //STYLE OF SPOT THE THIRD MA
#property indicator_width3  1          //LINE THICKNESS THE THIRD MA
#property indicator_color3  clrPurple    //LINE COLOR THE THIRD MA

//SET MA BUFFER TO STORE DATA
double buffer_mA200[];  //BUFFER FOR THE FIRST MA
double buffer_mA100[];  //BUFFER FOR THE SECOND MA
double buffer_mA50[];   //BUFFER FOR THE THIRD MA

//SET MA PERIOD
input int period_ma200 = 200;  //PERIOD FOR THE FIRST MA
input int period_ma100 = 100;  //PERIOD FOR THE SECOND MA
input int period_ma50  = 50;   //PERIOD FOR THE THIRD MA

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {

//SETTING BUFFER
   SetIndexBuffer(0, buffer_mA200, INDICATOR_DATA);  //INDEX 0 FOR MA200
   SetIndexBuffer(1, buffer_mA100, INDICATOR_DATA);  //INDEX 1 FOR MA100
   SetIndexBuffer(2, buffer_mA50, INDICATOR_DATA);   //INDEX 1 FOR MA50

//SETTING BARS TO START PLOTTING
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, period_ma200);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, period_ma100);
   PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, period_ma50);

//---
   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[])
  {

//CALCULATE THE MOVING AVERAGE FOR THE THE First MA (MA200)
   for(int i = period_ma200 - 1; i < rates_total; i++)
     {

      double sum = 0.0;
      for(int j = 0; j < period_ma200; j++)
        {
         sum += high[i - j];
        }

      buffer_mA200[i] = sum / period_ma200;

     }

//CALCULATE THE MOVING AVERAGE FOR THE THE SECOND MA (MA100)
   for(int i = period_ma100 - 1; i < rates_total; i++)
     {

      double sum = 0.0;
      for(int j = 0; j < period_ma100; j++)
        {
         sum += close[i - j];
        }
      buffer_mA100[i] = sum / period_ma100;

     }

//CALCULATE THE MOVING AVERAGE FOR THE THE THIRD MA (MA50)
   for(int i = period_ma50 - 1; i < rates_total; i++)
     {
      double sum = 0.0;
      for(int j = 0; j < period_ma50; j++)
        {
         sum += open[i - j];
        }
      buffer_mA50[i] = sum / period_ma50;
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }

解説

//SET MA PERIOD
input int period_ma200 = 200;  //PERIOD FOR THE FIRST MA
input int period_ma100 = 100;  //PERIOD FOR THE SECOND MA
input int period_ma50  = 50;   //PERIOD FOR THE THIRD MA

  • これらの入力変数は、それぞれの移動平均(MA)の期間を定義します。
  • 期間とは、移動平均の計算に使用される過去のローソク足の本数を指します。
  • period_ma200 = 200は、直近200本のローソク足を使用してMA200を計算することを意味します。
  • period_ma100 = 100は、直近100本のローソク足を使用してMA100を計算することを意味します。
  • period_ma50 = 50は、直近50本のローソク足を使用してMA50を計算することを意味します。
  • これらは入力変数であるため、トレーダーはコードを変更せずに、インジケーターの設定画面から自由に数値を調整することができます。

//SETTING BARS TO START PLOTTING
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, period_ma200);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, period_ma100);
   PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, period_ma50);

なぜこれが必要なのでしょうか?

  • 期間200の移動平均では、その値を計算するために過去200本のローソク足が必要なため、最初の200本より前には何もプロットできません。
  • PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, period_ma200);は、200本のローソク足が揃った後にのみ、MetaTraderにMA200の描画を開始するよう指示します。
  • PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, period_ma100);は、MA100に対して同様に、100本のローソク足以降に描画を開始するよう指定します。
  • PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, period_ma50);は、MA50を50本のローソク足以降に開始するように設定します。

図4:プロット開始

//+------------------------------------------------------------------+
//| 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[])

すべてのカスタムインジケーターにおける中心的な関数OnCalculate()は、新しいティックを受信したときや過去のデータが更新されたときに自動的に呼び出されます。この関数は、価格データを処理し、インジケーターバッファを更新するため、インジケーターの計算において極めて重要です。OnCalculate()はインジケーター専用に設計されており、CopyOpen()、CopyClose()、ArraySetAsSeries()のような他の手続きを使用することなく、過去の価格データに直接アクセスできます。これは、EAで使用されるOnTick()とは対照的です。

OnCalculate()とOnTick()の違い

特徴
OnCalculate()
OnTick()
使用場所
指標
EA
呼び出されるタイミング新しいティックが到着するかチャートが更新される
新しいティックが到着する
価格データへのアクセス
組み込み配列(open[]、close[]など)を使用
データを取得するにはCopyClose()などの関数が必要
用途
指標値を計算して更新する
取引ロジックを実行し、注文を出す
OnCalculate()のパラメータ
パラメータ
詳細
rates_total
チャート上で利用可能なローソク足(バー)の合計数
prev_calculated
以前に計算されたバーの数(パフォーマンスの最適化に役立つ)
time[]
各ローソク足のタイムスタンプ(例:2024.02.02 12:30)
open[]
各ローソク足の始値
high[]
各ローソク足の高値
low[]
各ローソク足の安値
close[]
各ローソク足の終値
tick_volume[]
ローソク内のティック(価格更新)数
volume[]
1本のローソク足内で取引された合計量
spread[]
各ローソクのスプレッド(売値と買値の差)
// CALCULATE THE MOVING AVERAGE FOR THE FIRST MA (MA200)
for(int i = period_ma200 - 1; i < rates_total; i++)
  {
   double sum = 0.0;
   for(int j = 0; j < period_ma200; j++)
     {
      sum += high[i - j];  // SUM OF HIGH PRICES OVER THE PERIOD
     }
   buffer_mA200[i] = sum / period_ma200;  // CALCULATE THE AVERAGE
  }

価格データを順に処理するforループを使って、最初の移動平均(MA200)を計算します。ループは「period_ma200 - 1」から開始するため、過去のデータが十分に揃っていて平均を計算可能です。rates_totalまでループが続きますが、これは提供される価格データの総数を意味します。このメソッドにより、存在しないデータ(負のインデックスなど)にアクセスするミスを防げます。チャート上のすべてのバーに対して移動平均が順に計算され、対応するインジケーターバッファが更新されます。

期間内(ここでは200)の高値の合計を保持するために、ループ内で変数sumを初期化します。入れ子のforループが直近200本のバーを0からperiod_ma200まで繰り返します。sum += high[i - j];で各繰り返しにおいて、特定のバーの高値をsumに加算します。インデックス「i - j」を用いることで、現在のバーiから遡った直近200本の高値を合計することが保証されます。この手法は指定期間内のすべての高値を効率的に合計します。

200期間の高値合計が求まったら、その合計を期間長で割って平均を算出します(buffer_mA200[i] = sum / period_ma200;)。この最終値が各バーの移動平均値となり、対応するbuffer_mA200のインデックスに保存されます。過去200本の高値の平均を取ることで、移動平均は価格変動を平滑化し、トレーダーが長期的なトレンドを見極めやすくします。他の移動平均(MA100、MA50)も異なる価格タイプ(終値、始値)や期間を用いていますが、同様の考え方で計算されます。

図5:MAライン

3.2. ローソク足形式の移動平均インジケーターの構築

このセクションでは、価格の動きをローソク足形式で表示する、従来とは異なるタイプの移動平均インジケーターを作成します。このインジケーターは5期間の移動平均を使用し、ラインではなくローソク足を用いて値を視覚的に表現します。この方法で移動平均データを表示することで、マーケットノイズを効果的に除去し、短期的なトレンドをより明確に捉えることが可能になります。これにより、移動平均計算の基本を維持しつつ、価格変動に対する独自の視点を提供できます。

ローソク足は、始値、終値、高値、安値という4つの基本的な価格要素で構成されています。ローソク足形式では、各期間に1つの価格だけを使うライン形式とは異なり、これら4つの価格それぞれに対して独立した移動平均の計算が必要です。したがって、1つのプロットに対して少なくとも4つのバッファが必要になります。それぞれが始値、終値、高値、安値の移動平均値を表します。このインジケーターの構成により、移動平均データが実際のローソク足パターンに近い形で表示されるため、視覚的な手がかりを活用した価格トレンドの分析が容易になります。

#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1

//---- plot ColorCandles
#property indicator_label1  "Candles"
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrGreen, clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- indicator buffers
double OpenBuffer[];
double HighBuffer[];
double LowBuffer[];
double CloseBuffer[];
double ColorBuffer[];

int period = 5;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0, OpenBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, HighBuffer, INDICATOR_DATA);
   SetIndexBuffer(2, LowBuffer, INDICATOR_DATA);
   SetIndexBuffer(3, CloseBuffer, INDICATOR_DATA);
   SetIndexBuffer(4, ColorBuffer, INDICATOR_COLOR_INDEX);

   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, period);

   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[])
  {

   if(rates_total < period)
     {
      Print("Error: Not enough bars to calculate.");
      return 0;
     }

   for(int i = period - 1; i < rates_total; i++)
     {

      if(i - period + 1 < 0)
         continue;

      double sumClose = 0.0;
      double sumOpen = 0.0;
      double sumHigh = 0.0;
      double sumLow = 0.0;

      for(int j = 0; j < period; j++)
        {
         int index = i - j;
         if(index < 0)
            continue; // Prevent out-of-bounds access

         sumClose += close[index];
         sumOpen += open[index];
         sumHigh += high[index];
         sumLow += low[index];
        }

      if(period > 0)
        {
         OpenBuffer[i] = sumOpen / period;
         HighBuffer[i] = sumHigh / period;
         LowBuffer[i] = sumLow / period;
         CloseBuffer[i] = sumClose / period;
        }
      else
        {
         Print("Error: Division by zero prevented.");
         return 0;
        }

      ColorBuffer[i] = (CloseBuffer[i] >= OpenBuffer[i]) ? 0 : 1;
     }

   return rates_total;
  }

解説

#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1

//---- plot ColorCandles
#property indicator_label1  "Candles"
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrGreen, clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- indicator buffers
double OpenBuffer[];
double HighBuffer[];
double LowBuffer[];
double CloseBuffer[];
double ColorBuffer[];

int period = 5;

このコードは、ローソク足形式で移動平均を表示するカスタムインジケーターのプロパティとバッファを定義します。通常、ローソク足には始値、高値、安値、終値の4つのバッファが必要ですが、本インジケーターでは各ローソク足の色を識別・保持する追加のバッファ(ColorBuffer)が必要なため、合計で5つのバッファを使用します。

インジケータープロパティ

  • #property indicator_separate_window:インジケーターをメインチャートではなく別ウィンドウに表示するよう指定する
  • #property indicator_buffers 5:使用するバッファの数を5に設定するローソク足には本来4つ(Open、High、Low、Close)のバッファで足りるが、ローソク足の色を指定するために5つ目のバッファが必要になる
  • #property indicator_plots 1:1つのプロットのみを持つインジケーターであることを示す。このプロットは色付きローソク足を描画する。

プロットと可視化の設定

  • indicator_label1 "Candles":プロットにCandlesというラベル名を付ける
  • indicator_type1 DRAW_COLOR_CANDLES:プロットタイプを色付きローソク足に設定する。DRAW_LINEとは異なり、このタイプはOpen、High、Low、Closeに加えて色インデックスが必要。
  • indicator_color1 clrGreen, clrRed:上昇ローソク足には緑色、下降ローソク足には赤色を割り当てる
  • indicator_style1 STYLE_SOLID:ローソク足の縁を実線で表示する
  • indicator_width1 1:ローソク足の縁の太さを1に設定する

なぜ4つではなく5つのバッファが必要なのか

一般的なローソク足の構成には、以下の4つのバッファが必要です。

  • OpenBuffer[]:移動平均の始値を格納
  • HighBuffer[]:移動平均の高値を格納
  • LowBuffer[]:移動平均の安値を格納
  • CloseBuffer[]:移動平均の終値を格納

しかし、本インジケーターではカラー付きローソク足を使用するため、追加で5つ目のバッファが必要になります。

  • ColorBuffer[]:色インデックスを格納(0=緑、1=赤)。  この追加バッファにより、移動平均が上昇(緑)または下降(赤)ローソク足で視覚的に表現されるようになり、価格パターンの識別が容易になる。
//--- indicator buffers mapping
SetIndexBuffer(0, OpenBuffer, INDICATOR_DATA);
SetIndexBuffer(1, HighBuffer, INDICATOR_DATA);
SetIndexBuffer(2, LowBuffer, INDICATOR_DATA);
SetIndexBuffer(3, CloseBuffer, INDICATOR_DATA);
SetIndexBuffer(4, ColorBuffer, INDICATOR_COLOR_INDEX);

PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, period);

移動平均をローソク足形式で保存するために、このコードセクションではインジケーターバッファをマッピングします。このローソク足タイプの移動平均では、従来のラインベースの形式(計算値を描画するために1つのバッファのみを使用)とは異なり、始値・高値・安値・終値に対応する4つのバッファ(OpenBuffer、HighBuffer、LowBuffer、CloseBuffer)を使用して、移動平均の各価格成分を保存します。

さらに、5つ目のバッファであるColorBufferを使用し、ローソク足の色(上昇=緑、下降=赤)を識別します。データを正しく処理・表示させるために、SetIndexBuffer()関数でそれぞれのバッファを個別のプロットインデックスに関連付けます。また、PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,period);により、十分な本数のバーが揃った後にのみ描画が開始されるように設定し、不完全または誤解を招くグラフィックを防ぎます。

if(rates_total < period)
  {
   Print("Error: Not enough bars to calculate.");
   return 0;
  }

for(int i = period - 1; i < rates_total; i++)
  {

   if(i - period + 1 < 0)
      continue;

   double sumClose = 0.0;
   double sumOpen = 0.0;
   double sumHigh = 0.0;
   double sumLow = 0.0;

   for(int j = 0; j < period; j++)
     {
      int index = i - j;
      if(index < 0)
         continue; // Prevent out-of-bounds access

      sumClose += close[index];
      sumOpen += open[index];
      sumHigh += high[index];
      sumLow += low[index];
     }

   if(period > 0)
     {
      OpenBuffer[i] = sumOpen / period;
      HighBuffer[i] = sumHigh / period;
      LowBuffer[i] = sumLow / period;
      CloseBuffer[i] = sumClose / period;
     }
   else
     {
      Print("Error: Division by zero prevented.");
      return 0;
     }

   ColorBuffer[i] = (CloseBuffer[i] >= OpenBuffer[i]) ? 0 : 1;
  }

return rates_total;

このコードセグメントは、計算を続行するのに十分な価格バーがあるかどうかを最初に確認します。「if(rates_total<period)」の条件によって、ユーザーが指定した期間に対して移動平均を計算するのに十分な過去のデータ(バー)があるかどうかを判断します。バーが不十分な場合、関数は0を返し、エラーメッセージを書き込みます。これは、十分なデータがなければ意味のある移動平均の計算をおこなえず、無理に行おうとすると不正確または誤解を招く統計につながる可能性があるため、重要なステップです。

十分なバーが確認された後、forループは「period-1」インデックスから始まり、rates_totalまで価格データを反復処理します。各バーは、指定された時点から始まり順に処理されます。このループでは、変数iが現在のバーのインデックスを表します。前の期間のバーの価格情報を使用して、各バーに対して移動平均を決定します。i-period+1が0未満の場合は、必要な本数のバーが揃っていないため、次の反復にスキップします。

ループ内で、sumClose、sumOpen、sumHigh、sumLowの4つの変数が0.0に初期化されます。これらの変数には、指定された期間内のそれぞれの価格データの累積合計が格納されます。期間内の各バーの価格情報は、もう一つのforループを使って収集され、今回は0から「period - 1」まで反復されます。現在のインデックスiからjを差し引くことで、内側のループは各過去バーを取得し、その期間における終値、始値、高値、安値の合計を算出します。ループは、配列の範囲外へのアクセスを防ぐために、「if(index < 0)」という条件を用いて不正なデータの処理を回避します。

ゼロ除算の問題を避けるために、コードはその期間の価格データを収集した後に、periodが0より大きいかどうかを判定します。期間が有効であれば、コードはその期間における始値、高値、安値、終値の平均を算出し、その結果をOpenBuffer、HighBuffer、LowBuffer、CloseBufferの各バッファに保存します。計算された値は、ローソク足の描画用データとしてこれらのバッファに格納されます。最後に、ローソク足の色がColorBufferを更新することで設定されます。終値が始値以上であれば、ローソク足は緑色(値0)で塗られ、これは強気トレンドを示します。終値が始値より小さければ、ローソク足は赤色(値1)で塗られ、これは弱気トレンドを示します。

OnCalculate関数の最後には、MetaTraderに対して正常に処理されたバー数を示すrates_totalの値が返されます。この値は後のOnCalculate呼び出し時にも重要で、処理済みのバー数を追跡し、リアルタイムデータの更新を正確に処理できるようにするために必要です。

図6:ローソク足MA

ローソク足形式を扱うことで、将来的に解説予定の平均足チャートなど、より高度なインジケーターの基礎も築くことができました。


結論

本記事では、カスタムインジケーターの作成、移動平均線の活用、ライン形式やローソク足形式などの異なるスタイルでのデータの可視化といった基本的な概念を紹介しました。また、バッファの使い方や、データを表現するためのプロットの設定方法についても解説しました。今後の記事では、より興味深いプロジェクトに焦点を当てていきます。初心者にとって最も効果的な学習方法は、プロジェクトベースのアプローチです。この方法では、この段階で不必要な詳細に圧倒されることなく、学習を管理しやすいステップに分割して進めることができます。このアプローチによって、段階的に進歩し、重要な概念をより深く理解できるようになります。

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

添付されたファイル |
最後のコメント | ディスカッションに移動 (2)
dhermanus
dhermanus | 30 5月 2025 において 07:12

お疲れ様でした。イスラエルだ。ありがとうございます。


あなたはprev_calculatedを利用していません。つまり、
あなたのコードは、実行中のティックごとに、すべての前の計算されたバーを再計算することになります。

Israel Pelumi Abioye
Israel Pelumi Abioye | 30 5月 2025 において 09:27
dhermanus #:

お疲れ様でした。イスラエルだ。感謝する。


あなたはprev_calculatedを利用していません。つまり、
あなたのコードは、実行中のティックごとに、前の計算されたバーをすべて再計算することになります。

こんにちは。
コメントありがとうございます。

ありがとうございます。
プライスアクション分析ツールキットの開発(第12回):External Flow (III)トレンドマップ プライスアクション分析ツールキットの開発(第12回):External Flow (III)トレンドマップ
市場の流れは、ブル(買い手)とベア(売り手)の力関係によって決まります。市場が反応する特定の水準には、そうした力が作用しています。中でも、フィボナッチとVWAPの水準は、市場の動きに強い影響を与える傾向があります。この記事では、VWAPとフィボナッチ水準に基づいたシグナル生成の戦略を一緒に探っていきましょう。
エキスパートアドバイザーの堅牢性テスト エキスパートアドバイザーの堅牢性テスト
戦略開発には、多くの複雑な要素が含まれていますが、これらの多くは初心者トレーダーには十分に伝えられていません。その結果、私自身を含め多くのトレーダーが、こうした教訓を痛みを伴う経験を通じて学ぶことになりました。この記事では、MQL5で戦略を開発する際に初心者トレーダーが直面しがちな一般的な落とし穴について、私の観察に基づいて解説します。EAの信頼性を見極め、簡単に実践できる方法で自作EAの堅牢性を検証するための、さまざまなヒントやコツ、具体例を紹介します。本記事の目的は、読者がEA購入時の詐欺を回避し、自身の戦略開発での失敗を未然に防げるよう支援することです。
MQL5での取引戦略の自動化(第6回):スマートマネートレーディングのためのオーダーブロック検出の習得 MQL5での取引戦略の自動化(第6回):スマートマネートレーディングのためのオーダーブロック検出の習得
この記事では、純粋なプライスアクション分析を用いてMQL5でオーダーブロック検出を自動化します。オーダーブロックの定義、検出の実装、自動売買への統合をおこない、最後に戦略のバックテストを通じてパフォーマンスを評価します。
ログレコードをマスターする(第5回):キャッシュとローテーションによるハンドラの最適化 ログレコードをマスターする(第5回):キャッシュとローテーションによるハンドラの最適化
この記事では、ハンドラへのフォーマッタ追加、実行サイクルを管理するためのCIntervalWatcherクラスの導入、キャッシュとファイルローテーションによる最適化、さらにパフォーマンステストおよび実用的な使用例を通じて、ログライブラリをさらに改善します。これらの機能強化により、さまざまな開発シナリオに柔軟に対応可能な、効率的でスケーラブルなロギングシステムが実現します。