目次
作るもの
チャートと別枠に表示する平均足インジケータ に、陽線(陰線)から陰線(陽線)に切替わったときにアラートを鳴らす機能を追加します。
参考サイト
実装
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;
}
//+------------------------------------------------------------------+
コメント