📉
TEMAを自作したい ①OnCalculateの違い
TEMAもMQL5で自作したいと思っているとすで実装されていました。
ソースを見てみると
TEMA.mq5
//+------------------------------------------------------------------+
//| TEMA.mq5 |
//| Copyright 2000-2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property description "Triple Exponential Moving Average"
#include <MovingAverages.mqh>
//--- indicator settings
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots 1
#property indicator_type1 DRAW_LINE
#property indicator_color1 DarkBlue
#property indicator_width1 1
#property indicator_label1 "TEMA"
#property indicator_applied_price PRICE_CLOSE
//--- input parameters
input int InpPeriodEMA=14; // EMA period
input int InpShift=0; // Indicator's shift
//--- indicator buffers
double TemaBuffer[];
double Ema[];
double EmaOfEma[];
double EmaOfEmaOfEma[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
void OnInit()
{
//--- indicator buffers mapping
SetIndexBuffer(0,TemaBuffer,INDICATOR_DATA);
SetIndexBuffer(1,Ema,INDICATOR_CALCULATIONS);
SetIndexBuffer(2,EmaOfEma,INDICATOR_CALCULATIONS);
SetIndexBuffer(3,EmaOfEmaOfEma,INDICATOR_CALCULATIONS);
//--- sets first bar from what index will be drawn
PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,3*InpPeriodEMA-3);
//--- sets indicator shift
PlotIndexSetInteger(0,PLOT_SHIFT,InpShift);
//--- name for indicator label
string short_name=StringFormat("TEMA(%d)",InpPeriodEMA);
IndicatorSetString(INDICATOR_SHORTNAME,short_name);
PlotIndexSetString(0,PLOT_LABEL,short_name);
}
//+------------------------------------------------------------------+
//| Triple Exponential Moving Average |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
if(rates_total<3*InpPeriodEMA-3)
return(0);
//---
int start;
if(prev_calculated==0)
start=0;
else
start=prev_calculated-1;
//--- calculate EMA
ExponentialMAOnBuffer(rates_total,prev_calculated,0,InpPeriodEMA,price,Ema);
//--- calculate EMA on EMA array
ExponentialMAOnBuffer(rates_total,prev_calculated,InpPeriodEMA-1,InpPeriodEMA,Ema,EmaOfEma);
//--- calculate EMA on EMA array on EMA array
ExponentialMAOnBuffer(rates_total,prev_calculated,2*InpPeriodEMA-2,InpPeriodEMA,EmaOfEma,EmaOfEmaOfEma);
//--- calculate TEMA
for(int i=start; i<rates_total && !IsStopped(); i++)
TemaBuffer[i]=3*Ema[i]-3*EmaOfEma[i]+EmaOfEmaOfEma[i];
//--- OnCalculate done. Return new prev_calculated.
return(rates_total);
}
//+------------------------------------------------------------------+
OnCaliculateの2つの形式
MQL5のOnCalculate
関数には、引数の形式が主に以下の2種類あります。
-
形式1: 4つの引数を持つ
OnCalculate
関数int OnCalculate(const int rates_total, // バーの総数 const int prev_calculated, // 前回の計算済みバー数 const int begin, // 必要な最小バー数 const double &price[]); // 入力価格データ
-
形式2: 10個の引数を持つ
OnCalculate
関数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[]); // スプレッド
これら2種類の形式の使用用途の違いを以下で説明します。
OnCalculate
関数(形式1)
1. 4つの引数の用途
-
シンプルなインジケータの作成に向いていそう:
- 単一の価格データ(
price[]
)を使用して計算するシンプルなインジケータに使用。 - 例: 移動平均(MA)、ボリンジャーバンド(BB)、単純なカスタム指標。
- 単一の価格データ(
-
計算対象のデータが1種類のみの場合:
-
close[]
(終値)やhigh[]
(高値)など、1種類のデータをインジケータに渡して計算する場合。
-
メリット
-
簡潔で分かりやすい:
- 必要な引数が少なく、シンプルなインジケータを作成する際のコードが短くなる。
- 一般的には
price[]
にclose[]
が渡されるため、明確に終値を扱うコードになる。
-
軽量な処理:
- 不要なデータ(例えば
open[]
やvolume[]
など)を渡さないため、計算処理が軽量。
- 不要なデータ(例えば
制限
-
利用可能なデータが限定される:
-
price[]
以外のデータ(例えばhigh[]
やvolume[]
)が必要な場合、この形式では対応できない。 - カスタムインジケータで特定の計算ロジックを実現するのが難しい。
-
-
拡張性が低い:
- 将来的に異なるデータ(例えば
tick_volume[]
)を利用する可能性がある場合、この形式では柔軟性が低い。
- 将来的に異なるデータ(例えば
OnCalculate
関数(形式2)
2. 10個の引数の用途
-
複雑なインジケータの作成:
- 複数の価格データ(
open[]
,high[]
,low[]
,close[]
)や、volume[]
、spread[]
などを利用するカスタムインジケータに使用します。 - 例: 一目均衡表(Ichimoku)、ピボットポイント、ボリューム加重平均(VWAP)。
- 複数の価格データ(
-
複数の価格データが必要な場合:
- 高値・安値・終値などを組み合わせた計算が必要なインジケータ。
-
補助データが必要な場合:
- ティックボリュームやスプレッドなど、価格以外のデータを使った分析が必要なインジケータ。
メリット
-
柔軟性が高い:
- 複数のデータ(
open[]
,high[]
,low[]
,close[]
)やtick_volume[]
、volume[]
を利用できるため、高度な計算が可能。 - 例えば、高値と安値の中央値を利用するインジケータを簡単に実装可能。
- 複数のデータ(
-
時間情報を活用可能:
-
time[]
(バーごとのタイムスタンプ)が利用可能なので、日付や時刻に基づく計算(例: ピボットポイント、セッション区分など)に対応できる。
-
-
複数データを同時に利用:
- 高値・安値・終値の複合的なインジケータ(例: ATR, ADX)を簡単に作成可能。
制限
-
コードが複雑になる:
- 引数が増えるため、コードが長くなりやすい。
- 必要なデータを選択的に利用する必要がある。
-
処理負荷が増大:
- 全てのデータが渡されるため、単純なインジケータでは不要なデータを処理する可能性がある。
比較表: 形式1 vs 形式2
項目 | 形式1(4引数) | 形式2(10引数) |
---|---|---|
利用シーン | シンプルなインジケータ | 複雑なインジケータ |
価格データの利用 | 単一(price[] のみ) |
複数(open[] , high[] , low[] , close[] ) |
補助データの利用 | 利用不可 |
volume[] , spread[] , time[] が利用可能 |
柔軟性 | 低い | 高い |
コードの簡潔さ | 簡潔 | 複雑になりがち |
パフォーマンス負荷 | 低い | 高い(全データを渡すため) |
典型的なインジケータ例 | 移動平均(SMA, EMA)、ボリンジャーバンド | ATR、ADX、一目均衡表、VWAP |
どちらを使うべきか
形式1(4引数)を選ぶ場合
- 移動平均のようにシンプルな計算を行う場合。
- 高値や安値、ボリュームなど、価格以外のデータを使わない場合。
- 計算の軽量化が重要な場合。
形式2(10引数)を選ぶ場合
- 複数の価格データや補助データ(ボリュームやスプレッド)を使用する場合。
- 高度なインジケータ(例: ATR, ADX, ピボットポイント)を作成する場合。
- 日付や時間に基づく計算が必要な場合。
まとめ
- 形式1(4引数)は、シンプルなインジケータに適しており、特定の価格データだけを使いたい場合に有効。
- 形式2(10引数)は、柔軟性が必要な場合や、複数の価格データや補助データを活用する複雑なインジケータに適している。
どちらを選ぶかは、インジケータの用途や複雑さに応じて使い分けするよう。
自分はTHMAやTEMAをEAで使っていきたいと思うので、形式2で書き直してみたいと思います。
Discussion