【MQL4関数】OnCalculate関数とは?ロウソク足が動くたびに実行されるイベント関数

【中級編】MQLプログラムの読み方・書き方
朝日奈りさ
朝日奈りさ

OnCalculate関数は、ロウソク足が動くたびに実行されるイベント関数です。同じような関数として、OnStart関数とOnTick関数がありますが、OnCalculate関数はインジケータ専用です。

OnCalculate関数とは

「インジケータを作ってみたい!」

という方は、OnCalculate関数を勉強しましょう!

OnCalculate関数は、イベント関数の一つで、ロウソク足が動くたびに実行される関数です。

ロウソク足が動くたびに実行される関数として、OnCalculate関数の他にも、OnStart関数とOnTick関数があります。

それぞれ以下のように使い分けができますので、エラーなどを出さないためにも、適切な関数を使うと良いでしょう。

関数名適切なプログラム
OnStartスクリプト
OnTick自動売買(EA)
OnCalculateインジケータ

今回は、OnCalculate関数に注目して解説していきます。

インジケータを新規作成したときのプログラム

インジケータを新規作成すると、以下のようなプログラムが自動作成されます。

何やら難しそうな関数がありますね。

今回解説するOnCalculate関数です。

//+------------------------------------------------------------------+
//|                                    SampleMQL_ind_OnCalculate.mq4 |
//|                                     Copyright 2022, Asahina Risa |
//|                                      https://mql-programing.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, Asahina Risa"
#property link      "https://mql-programing.com/"
#property version   "1.00"
#property strict
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   
//---
   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[])
  {
//---
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

新規作成すると、このように、すでにOnInit関数・OnCalculate関数が記述されています。

OnCalculate関数は、24行目にあります。

OnCalculate関数の特徴

OnCalculate関数はイベント関数なので、イベントが起こったときに実行されます。

そのイベントとは、「ロウソク足が動いたとき」です。

つまり、チャートの価格が変動するたびに実行されます。

そのため、1秒間で何度も実行されることもあれば、1分以上も実行されない場合もあります。

もし、一定時間ごとに実行させたいプログラムがある場合は、OnTimer関数を利用すると良いでしょう。

OnCalculate関数は、インジケータ専用の関数です。

自動売買やスクリプトでは実行できない関数です。

OnCalculate関数の書き方

OnCalculate関数の使い方は、基本的な関数と同じです。

関数をマスターしていない方はこちらの記事が参考になります。

基本的な書き方

OnCalculate関数は、かなり複雑な関数です。

引数は10つ

戻り値はint型です。

OnCalculate関数の基本的な書き方は以下の通りです。

見やすくするため、10つの引数を改行しています。

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[]
  )
  {
   return(rates_total);
  }

戻り値はint型なので、retuenを書く必要がありますが、必ず「rates_total」を戻すようにしてください。

他の値を戻すと、エラーの原因になります。

戻り値

int型

変数「rates_total」を戻すこと。

引数

引数は難しいので、詳しく見ていきます。

まずは、前提として、OnCalculate関数は開発者が使う関数ではなく、システムが使う関数です。

そのため、引数はシステムが自動的に入力しますので、OnCalculate関数で自動入力された引数を、開発者がOnCalculate関数内で利用するというイメージです。

それでは、引数を1つずつ確認していきましょう。

難しいので、サンプルプログラムを作りながら解説していきます。

サンプルプログラムは、RSIを使った矢印サインツールを作っていきます。

①const int rates_total

引数1つ目です。int型です。

const属性が付いているので、変数の値を、関数内で変更することはできません。

&属性が付いているので、関数内で変数の値を変更すると、関数に渡される前の変数の値も変更されます。

今回はconst属性が付いているので、変更することはできません。

この変数rates_totalには、インジケータで計算するロウソク足(Bar)の総数が入っています。

MT4の設定で、チャートの最大バー数を1000に設定していたなら、1000が入ります。

②const int prev_calculate

引数2つ目です。int型です。

const属性が付いているので、変数の値を、関数内で変更することはできません。

&属性が付いているので、関数内で変数の値を変更すると、関数に渡される前の変数の値も変更されます。

今回はconst属性が付いているので、変更することはできません。

この変数prev_calculateには、このインジケータで、すでに計算したロウソク足(Bar)の数が入っています。

prev_calculateは、OnCalculate関数が呼び出されるごとに、1ずつ増えていき、最終的にrates_totalと同じ値になります。

そのため、多くの開発者は、まだ計算されていないロウソク足の数を計算するのに、以下のようなプログラミングをします。

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;


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

さらに、まだ計算されていないロウソク足をfor文で回し、過去全てのロウソク足を計算します。

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;

//for文で、過去のロウソク足から計算する
   for(int i = limit; i >= 0; i--)
     {

     }

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

③const datetime &time[]

引数3つ目です。datetime型です。

const属性が付いているので、変数の値を、関数内で変更することはできません。

&属性が付いているので、関数内で変数の値を変更すると、関数に渡される前の変数の値も変更されます。

今回はconst属性が付いているので、変更することはできません。

この変数timeには、インジケータの計算対象のロウソク足の日付が入っています。

④const double &open[]

引数4つ目です。double型です。

const属性が付いているので、変数の値を、関数内で変更することはできません。

&属性が付いているので、関数内で変数の値を変更すると、関数に渡される前の変数の値も変更されます。

今回はconst属性が付いているので、変更することはできません。

この変数openには、インジケータの計算対象のロウソク足の始値が入っています。

⑤const double &high[]

引数5つ目です。double型です。

const属性が付いているので、変数の値を、関数内で変更することはできません。

&属性が付いているので、関数内で変数の値を変更すると、関数に渡される前の変数の値も変更されます。

今回はconst属性が付いているので、変更することはできません。

この変数highには、インジケータの計算対象のロウソク足の高値が入っています。

⑥const double &low[]

引数6つ目です。double型です。

const属性が付いているので、変数の値を、関数内で変更することはできません。

&属性が付いているので、関数内で変数の値を変更すると、関数に渡される前の変数の値も変更されます。

今回はconst属性が付いているので、変更することはできません。

この変数lowには、インジケータの計算対象のロウソク足の底値が入っています。

⑦const double &close[]

引数7つ目です。double型です。

const属性が付いているので、変数の値を、関数内で変更することはできません。

&属性が付いているので、関数内で変数の値を変更すると、関数に渡される前の変数の値も変更されます。

今回はconst属性が付いているので、変更することはできません。

この変数closeには、インジケータの計算対象のロウソク足の終値が入っています。

⑧const long &tick_volume[]

引数8つ目です。long型です。

const属性が付いているので、変数の値を、関数内で変更することはできません。

&属性が付いているので、関数内で変数の値を変更すると、関数に渡される前の変数の値も変更されます。

今回はconst属性が付いているので、変更することはできません。

この変数tick_volumeには、インジケータの計算対象のロウソク足の出来高が入っています。

⑨const long &volume[]

引数9つ目です。long型です。

const属性が付いているので、変数の値を、関数内で変更することはできません。

&属性が付いているので、関数内で変数の値を変更すると、関数に渡される前の変数の値も変更されます。

今回はconst属性が付いているので、変更することはできません。

この変数volumeには、インジケータの計算対象のロウソク足の実際の出来高が入っています。

しかしFXでは値は入ってきません。

株やCFDなどの商品の場合、値が入ってきます。

⑩const int &spread[]

引数10つ目です。int型です。

const属性が付いているので、変数の値を、関数内で変更することはできません。

&属性が付いているので、関数内で変数の値を変更すると、関数に渡される前の変数の値も変更されます。

今回はconst属性が付いているので、変更することはできません。

この変数spreadには、インジケータの計算対象のロウソク足の平均スプレッドが入っています。

OnCalculate関数のサンプルプログラム

サンプルプログラムの全体は、こちらになります。

このプログラムは、RSIを計算し、買いの条件に当てはまると上矢印を表示し、売りの条件に当てはまると下矢印を表示します。

普段のトレードでも使える内容となっているので、工夫して使ってみてください。

インジケータなので、インジケータフォルダに入れてご利用ください。

//+------------------------------------------------------------------+
//|                                    SampleMQL_ind_OnCalculate.mq4 |
//|                                     Copyright 2022, Asahina Risa |
//|                                      https://mql-programing.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, Asahina Risa"
#property link      "https://mql-programing.com/"
#property version   "1.00"
#property strict

//チャート上に矢印を表示したいので、これを設定
#property indicator_chart_window

//インジケータの説明
#property description "ダウンロードありがとうございます!"
#property description "朝日奈りさです^^"
#property description "投資は自己責任です。余剰資金で行うようにしましょう。"



/*
RSIを使ったサインツールです。
サンプルですので、改変などご自由に^^
*/


//矢印や線の種類の数を設定
//今回は矢印を2種類表示させたいので、2を設定
#property indicator_buffers 2

//1つ目の矢印の色を設定
#property indicator_color1 clrMagenta
//2つ目の矢印の色を設定
#property indicator_color2 clrDodgerBlue

//1つ目の矢印の大きさを設定
#property indicator_width1 3
//2つ目の矢印の大きさを設定
#property indicator_width2 3

//外部入力
input int RSI_TERM = 14;


//表示する矢印の情報を入れる配列
double bufBuy[];
double bufSell[];

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


//バッファの割り当て
//このあたりがややこしいですが、画面に表示させるための準備をしています。
//バッファに割り当てることで、Open[]やClose[]のような感じに使えるようになります。

//買い矢印の情報を入れる配列を設定
   SetIndexBuffer(0, bufBuy);
//スタイルは矢印に設定
   SetIndexStyle(0, DRAW_ARROW);
//図形の種類を設定(ここでは上矢印)
   SetIndexArrow(0, 233);
//図形の名前を設定
   SetIndexLabel(0, "Buy Signal");

//以下売り矢印の設定
   SetIndexBuffer(1, bufSell);
   SetIndexStyle(1, DRAW_ARROW);
   SetIndexArrow(1, 234);
   SetIndexLabel(1, "Sell Signal");


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

//今回はRSIを計算する分だけ、表示させる数を減らす
   limit = limit - RSI_TERM;

//for文で、過去のロウソク足から計算する
   for(int i = limit; i >= 0; i--)
     {

      //RSIを計算
      double rsi = iRSI(_Symbol, PERIOD_CURRENT, RSI_TERM, PRICE_CLOSE, i);

      //買いシグナルの条件
      if(rsi < 30)
         bufBuy[i] = low[i];

      //売りシグナルの条件
      if(rsi > 70)
         bufSell[i] = high[i];

     }



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

まとめ

OnCalculate関数は、「ロウソク足が動いたとき」に実行されるイベント関数です。

インジケータでのみ動作します。

関数の見た目は複雑で、さらに動き方も複雑なので、インジケータを作るのを諦めた方も多いと思います。

ですが、使ってみると、書き方のパターンがある程度決まっているので、ちょっとしたものであれば、まずはコピペでやってみてください。

何となく動きがわかってきたら、少しプログラムを変えてみて、根気強く勉強していきましょう。