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関数は、「ロウソク足が動いたとき」に実行されるイベント関数です。
インジケータでのみ動作します。
関数の見た目は複雑で、さらに動き方も複雑なので、インジケータを作るのを諦めた方も多いと思います。
ですが、使ってみると、書き方のパターンがある程度決まっているので、ちょっとしたものであれば、まずはコピペでやってみてください。
何となく動きがわかってきたら、少しプログラムを変えてみて、根気強く勉強していきましょう。