📉

TEMAを自作したい ①OnCalculateの違い

2024/12/16に公開

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. 形式1: 4つの引数を持つOnCalculate関数

    int OnCalculate(const int rates_total,      // バーの総数
                    const int prev_calculated,  // 前回の計算済みバー数
                    const int begin,            // 必要な最小バー数
                    const double &price[]);     // 入力価格データ
    
  2. 形式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種類の形式の使用用途の違いを以下で説明します。


1. 4つの引数のOnCalculate関数(形式1)

用途

  • シンプルなインジケータの作成に向いていそう:
    • 単一の価格データ(price[])を使用して計算するシンプルなインジケータに使用。
    • 例: 移動平均(MA)、ボリンジャーバンド(BB)、単純なカスタム指標。
  • 計算対象のデータが1種類のみの場合:
    • close[](終値)やhigh[](高値)など、1種類のデータをインジケータに渡して計算する場合。

メリット

  1. 簡潔で分かりやすい:

    • 必要な引数が少なく、シンプルなインジケータを作成する際のコードが短くなる。
    • 一般的にはprice[]close[]が渡されるため、明確に終値を扱うコードになる。
  2. 軽量な処理:

    • 不要なデータ(例えばopen[]volume[]など)を渡さないため、計算処理が軽量。

制限

  1. 利用可能なデータが限定される:

    • price[]以外のデータ(例えばhigh[]volume[])が必要な場合、この形式では対応できない。
    • カスタムインジケータで特定の計算ロジックを実現するのが難しい。
  2. 拡張性が低い:

    • 将来的に異なるデータ(例えばtick_volume[])を利用する可能性がある場合、この形式では柔軟性が低い。

2. 10個の引数のOnCalculate関数(形式2)

用途

  • 複雑なインジケータの作成:

    • 複数の価格データ(open[], high[], low[], close[])や、volume[]spread[]などを利用するカスタムインジケータに使用します。
    • 例: 一目均衡表(Ichimoku)、ピボットポイント、ボリューム加重平均(VWAP)。
  • 複数の価格データが必要な場合:

    • 高値・安値・終値などを組み合わせた計算が必要なインジケータ。
  • 補助データが必要な場合:

    • ティックボリュームやスプレッドなど、価格以外のデータを使った分析が必要なインジケータ。

メリット

  1. 柔軟性が高い:

    • 複数のデータ(open[], high[], low[], close[])やtick_volume[]volume[]を利用できるため、高度な計算が可能。
    • 例えば、高値と安値の中央値を利用するインジケータを簡単に実装可能。
  2. 時間情報を活用可能:

    • time[](バーごとのタイムスタンプ)が利用可能なので、日付や時刻に基づく計算(例: ピボットポイント、セッション区分など)に対応できる。
  3. 複数データを同時に利用:

    • 高値・安値・終値の複合的なインジケータ(例: ATR, ADX)を簡単に作成可能。

制限

  1. コードが複雑になる:

    • 引数が増えるため、コードが長くなりやすい。
    • 必要なデータを選択的に利用する必要がある。
  2. 処理負荷が増大:

    • 全てのデータが渡されるため、単純なインジケータでは不要なデータを処理する可能性がある。

比較表: 形式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