目次
作るもの
チャートと別枠に表示する平均足インジケータ に、陽線(陰線)から陰線(陽線)に切替わったときにアラートを鳴らす機能を追加します。
参考サイト
実装
input string    AlertSound = "alert.wav";   // Sound
datetime prevDt = 0;
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[])
{
    (省略)
    MqlDateTime dt;
    TimeToStruct(time[rates_total - 1], dt);
    MqlDateTime pdt;
    TimeToStruct(prevDt, pdt);
    if (dt.min != pdt.min)
    {
        prevDt = time[rates_total - 1];
        if (((ExtOBuffer[rates_total - 3] > ExtCBuffer[rates_total - 3]) &&
             (ExtOBuffer[rates_total - 2] < ExtCBuffer[rates_total - 2])) ||
            ((ExtOBuffer[rates_total - 3] < ExtCBuffer[rates_total - 3]) &&
             (ExtOBuffer[rates_total - 2] > ExtCBuffer[rates_total - 2])))
        {
            PlaySound(AlertSound);
            prevDt = time[rates_total - 1];
        }
    }
    return rates_total;
}音声ファイル
音声ファイルは、(MT5のインストール先)\Sounds フォルダ、または Soundsフォルダのサブフォルダに格納する必要があります。
私の環境では、C:\Program Files\OANDA MetaTrader 5\Sounds でした。
今回は、このフォルダにデフォルトで入っている alert.wav を使用します。
足確定の判定
OnCalculate() の引数 time の分の部分が変わったら、足が確定したと見なしています。
すみません。分足でしか機能しません。
1時間以上の時間軸で動作確認するのが面倒で、端折りました。(´-∀-`;)
音声ファイルの再生
音声ファイルは PlaySound関数で再生できます。
PlaySound関数の定義は以下のとおり。
bool PlaySound(
  string  filename      // ファイル名
);
filename には、ファイル名を指定します。
サブフォルダ内に格納している場合は、(サブフォルダ名)\\(音声ファイル名) を指定します。
今回はサブフォルダを使用しないので、alert.wav だけ指定しています。
このインジケータをチャートに追加すると、下図のタイミングでアラートが鳴ります。

これで、テンションが上がるアラートを鳴らせますね!
コード全体
//+------------------------------------------------------------------+
//|                                         Heikin-Ashi_SubFrame.mq5 |
//|                                            Copyright 2024, Hailu |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
// 参考: Heiken_Ashi.mql5
#property copyright "Copyright 2024, Hailu"
#property link      "https://www.mql5.com"
#property version   "1.01"
#property indicator_separate_window
#property indicator_minimum 0
#property indicator_maximum 1
#property indicator_buffers 9
#property indicator_plots   1
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  Red, DodgerBlue
#property indicator_label1  "Upper/Lower"
input string    AlertSound = "alert.wav";   // Sound
double ExtOBuffer[];
double ExtHBuffer[];
double ExtLBuffer[];
double ExtCBuffer[];
double ExtColorBuffer[];
double bufOpen[];
double bufHigh[];
double bufLow[];
double bufClose[];
int hHeiken = 0;
datetime prevDt = 0;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
    // 平均足インジケータを作成
    hHeiken = iCustom(NULL, 0, "Examples\\Heiken_Ashi");
    if (hHeiken == INVALID_HANDLE)
    {
        PrintFormat("[E] Failed to create Heiken_Ashi indicator. [%d]", GetLastError());
        return INIT_FAILED;
    }
    SetIndexBuffer(0, ExtOBuffer, INDICATOR_DATA);
    SetIndexBuffer(1, ExtHBuffer, INDICATOR_DATA);
    SetIndexBuffer(2, ExtLBuffer, INDICATOR_DATA);
    SetIndexBuffer(3, ExtCBuffer, INDICATOR_DATA);
    SetIndexBuffer(4, ExtColorBuffer, INDICATOR_COLOR_INDEX);
    IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
    IndicatorSetString(INDICATOR_SHORTNAME, "Heikin-Ashi");
    PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);
    SetIndexBuffer(5, bufOpen, INDICATOR_CALCULATIONS);
    SetIndexBuffer(6, bufHigh, INDICATOR_CALCULATIONS);
    SetIndexBuffer(7, bufLow, INDICATOR_CALCULATIONS);
    SetIndexBuffer(8, bufClose, INDICATOR_CALCULATIONS);
    prevDt = 0;
    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 start = prev_calculated - 1;
    if(prev_calculated == 0)
    {
        ExtLBuffer[0] = 0;
        ExtHBuffer[0] = 0;
        ExtOBuffer[0] = 0;
        ExtCBuffer[0] = 0;
        start = 1;
    }
    // 平均足を取得
    CopyBuffer(hHeiken, 0, 0, rates_total, bufOpen);
    CopyBuffer(hHeiken, 1, 0, rates_total, bufHigh);
    CopyBuffer(hHeiken, 2, 0, rates_total, bufLow);
    CopyBuffer(hHeiken, 3, 0, rates_total, bufClose);
    // 正規化した平均足を設定
    for(int i = start; i < rates_total; i++)
    {
        // 最小値と最大値を求める
        double min = low[i];
        double max = high[i];
    
        for (int j = 1; j <= 100; j++)
        {
            int idx = i - j;
            if (idx < 0)
                break;
    
            min = MathMin(min, low[idx]);
            max = MathMax(max, high[idx]);
        }
        double pw = max - min;
        // 正規化
        ExtOBuffer[i] = (bufOpen[i] - min) / pw;
        ExtHBuffer[i] = (bufHigh[i] - min) / pw;
        ExtLBuffer[i] = MathMax((bufLow[i] - min) / pw, 0) + 0.000001;
        ExtCBuffer[i] = (bufClose[i] - min) / pw;
        // 色
        if (bufOpen[i] < bufClose[i])
            ExtColorBuffer[i] = 0.0;
        else
            ExtColorBuffer[i] = 1.0;
    }
    MqlDateTime dt;
    TimeToStruct(time[rates_total - 1], dt);
    MqlDateTime pdt;
    TimeToStruct(prevDt, pdt);
    if (dt.min != pdt.min)
    {
        prevDt = time[rates_total - 1];
        if (((ExtOBuffer[rates_total - 3] > ExtCBuffer[rates_total - 3]) &&
             (ExtOBuffer[rates_total - 2] < ExtCBuffer[rates_total - 2])) ||
            ((ExtOBuffer[rates_total - 3] < ExtCBuffer[rates_total - 3]) &&
             (ExtOBuffer[rates_total - 2] > ExtCBuffer[rates_total - 2])))
        {
            PlaySound(AlertSound);
            prevDt = time[rates_total - 1];
        }
    }
    return rates_total;
}
//+------------------------------------------------------------------+
			
			
			
			
			
			
			
コメント