📉

TEMAを自作したい ②ChatGPTはすごい

2024/12/16に公開

前回はTEMAで使用されているOnCalculate関数の引数の違いについてみていきました。

実装されていたものは引数が4つでしたが10個のものに書き直そうとしていました。

以下まるっとChatGPTに教えてもらったものです。

以下は、指定されたコードを**形式2(10引数のOnCalculate関数)**に書き直したバージョンです。この形式では、open[], high[], low[], close[], volume[] など複数のデータを扱えるようになります。


形式2で書き直した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 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 < 3 * InpPeriodEMA - 3)
      return(0);

   int start;
   if(prev_calculated == 0)
      start = 0; // 初回計算
   else
      start = prev_calculated - 1; // 以前の計算から続けて実行

   //--- 終値を利用してEMAを計算
   ExponentialMAOnBuffer(rates_total, prev_calculated, 0, InpPeriodEMA, close, Ema);

   //--- EMA(Ema)の値を用いて、2段階目のEMAを計算
   ExponentialMAOnBuffer(rates_total, prev_calculated, InpPeriodEMA - 1, InpPeriodEMA, Ema, EmaOfEma);

   //--- 3段階目のEMAを計算
   ExponentialMAOnBuffer(rates_total, prev_calculated, 2 * InpPeriodEMA - 2, InpPeriodEMA, EmaOfEma, EmaOfEmaOfEma);

   //--- TEMAを計算
   for(int i = start; i < rates_total && !IsStopped(); i++)
      TemaBuffer[i] = 3 * Ema[i] - 3 * EmaOfEma[i] + EmaOfEmaOfEma[i];

   //--- 計算完了、次回の計算位置を返す
   return(rates_total);
  }
//+------------------------------------------------------------------+

変更点と解説

1. 引数の変更

  • OnCalculate 関数を形式2(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[])
    
    • 元のprice[]close[]に置き換えています。
    • open[], high[], low[], volume[]など、追加のデータを利用する場合に対応可能。

2. 価格データの選択

  • 元のprice[]の代わりにclose[]を使用。
    ExponentialMAOnBuffer(rates_total, prev_calculated, 0, InpPeriodEMA, close, Ema);
    
    • 必要に応じて、open[]high[]などに変更可能。

3. 柔軟性の向上

  • 形式2を採用したことで、open[], high[], low[], tick_volume[] など複数のデータを必要とするインジケータに発展させる基盤を整備。

4. オリジナルコードの構造を維持

  • TEMAの計算フロー(3段階のEMAを計算して結果を組み合わせる)をそのまま維持。

使用例

形式2の利点を活かす方法

  • 高値と安値の平均でTEMAを計算する:

    double hl2[rates_total];
    for(int i = 0; i < rates_total; i++)
        hl2[i] = (high[i] + low[i]) / 2.0;
    
    ExponentialMAOnBuffer(rates_total, prev_calculated, 0, InpPeriodEMA, hl2, Ema);
    
  • ティックボリュームに基づく分析を追加:

    for(int i = start; i < rates_total && !IsStopped(); i++)
        if(tick_volume[i] > 1000) // 高ボリューム時に特定の処理を実行
           TemaBuffer[i] = 3 * Ema[i] - 3 * EmaOfEma[i] + EmaOfEmaOfEma[i];
    

まとめ

  • 形式2(10引数)を使用することで、close[]以外のデータにもアクセスでき、柔軟なインジケータ作成が可能になります。
  • この修正版では、オリジナルのTEMA計算フローを維持しつつ、close[]を用いたシンプルな実装となっています。
  • 必要に応じてhigh[]low[]を使ったカスタマイズにも対応可能です。


ちゃんと出力できました。
もうなんだか、考えることをやめてしまいそうですね、、、

Discussion