今回の概要
今回は、インジケータからSlackに通知するプログラムを紹介します。
前回紹介した「インジケータからLINEに簡単通知」の記事と同様、「WinAPIをシェル実行関数(ShellExecuteW)でcurlを実行する」という方法を使ってプログラムを作成してきたいと思います。
Slack通知をするための準備作業
Slackに通知するための方法はいくつかありますが、今回は一番簡単なIncoming Webhooksを利用します。Incoming Webhooksを利用するためには、専用のWebhook URLを作成し、MQLコードに設定する必要があります。
Webhook URLの作成手順については色々なサイトで解説があるので、当記事では説明を割愛します。Slack公式サイトの手順や、日本語で説明しているこちらのサイトなどを参考にして、Webhook URLを準備してください。
MQL5コード
Slack通知するMQL5コードを紹介します。今回のコードは
- Slack通知用クラス(CNotifySlack.mqh)
- Slack通知確認用インジケータ(IndicatorNotifySlack.mq5)
の2本になります。Slack通知関連のロジックは、インジケータ以外(EAやスクリプト)からも簡単に呼び出せるように、クラスライブラリ化しました。
Slack通知用クラス(CNotifySlack.mqh)
コード
//+------------------------------------------------------------------+
//| CNotifySlack.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#import "shell32.dll"
int ShellExecuteW(int hWnd,string lpVerb,string lpFile,string lpParameters,string lpDirectory,int nCmdShow);
#import
//+------------------------------------------------------------------+
//|
//| [Slack通知用クラス]
//|
//+------------------------------------------------------------------+
class CNotifySlack
{
private:
public:
//|---------------------------------------------------------------+
//| メンバ変数
//|---------------------------------------------------------------+
string m_curl_path;
string m_webhook_url;
//|---------------------------------------------------------------+
//| コンストラクタ、デストラクタ
//|---------------------------------------------------------------+
CNotifySlack();
~CNotifySlack() {};
//|---------------------------------------------------------------+
//| メンバ関数
//|---------------------------------------------------------------+
//| curlの実行コマンドパス
void CurlPath(string sArgValue) { this.m_curl_path = sArgValue; };
//| SlackのWebhookURL
void WebhookURL(string sArgValue) { this.m_webhook_url = sArgValue; };
//| Slack通知実行
void Notify(string, bool);
};
//+------------------------------------------------------------------+
//| [コンストラクタ]
//+------------------------------------------------------------------+
CNotifySlack::CNotifySlack()
{
this.m_curl_path="c:\\Windows\\System32\\curl.exe";
this.m_webhook_url="https://hooks.slack.com/services/XXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
}
//+------------------------------------------------------------------+
//| [メンバ関数]
//| Slack通知実行
//+------------------------------------------------------------------+
void CNotifySlack::Notify(
string sArgMessage, // 通知メッセージ
bool bAddMention // メッセージをメンションするかどうか
)
{
string sCommand = "";
string sMention = "";
if(bAddMention == true)
{
sMention="^<!channel^>";
}
StringConcatenate(
sCommand,
"/c ",
this.m_curl_path,
" -X POST --data-urlencode \"payload={",
"\\\"text\\\": \\\"",sMention, sArgMessage,"\\\"}\" ",
this.m_webhook_url);
ShellExecuteW(0,"","cmd.exe",sCommand,"",5);
}
コード解説
10~12行目
Windowsのコマンドプロンプトを叩くために必要なWindowsAPIを定義しています。
40~44行目
メンバ変数設定用の関数です。メンバ変数をpublicで定義しているので、この関数群は定義しなくても大丈夫ですが、気になる方はメンバ変数をprivateにするか、当関数群を削除しても問題ありません。
56~57行目
クラスのコンストラクタでSlack Notifyを利用する際に必要な固定値を設定しています。
56行目のcurlの実行コマンドパスは動作環境に合わせて修正してください。
57行目には、準備作業で発行したWebhook URLを設定してください。
69~85行目
Slackの通知コマンドです。Slack Incoming Webhookのインターフェース仕様に合わせてパラメータを指定して通知をしています。
Slack通知確認用インジケータ(IndicatorNotifySlack.mq5)
コード
//+------------------------------------------------------------------+
//| IndicatorNotifySlack.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property indicator_chart_window
#include "CNotifySlack.mqh"
#property indicator_buffers 1
#property indicator_plots 1
#property indicator_type1 DRAW_LINE
#property indicator_style1 STYLE_SOLID
#property indicator_color1 clrRed
#property indicator_width1 1
double bufHigh[];
CNotifySlack NotifySlack;
//+------------------------------------------------------------------+
//| 【初期化関数】
//| ・チャートの初期表示時、または時間足変更等のチャート初期化が必要な
//| タイミングで呼び出される。
//+------------------------------------------------------------------+
int OnInit()
{
ArraySetAsSeries(bufHigh, true);
ArrayInitialize(bufHigh, 0);
SetIndexBuffer(0, bufHigh, INDICATOR_DATA);
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 【計算イベント関数】
//| ・ローソク足に変化が発生する毎に呼び出される。
//+------------------------------------------------------------------+
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[])
{
//+------------------------------------------------------------------+
//| 1. 新規チャートのインジケータ値がまだ計算されていない場合
//| → 過去チャートのインジケータ値を計算する。
//+------------------------------------------------------------------+
if(prev_calculated == 0)
{
for(int i=rates_total-1; i>=0; i--)
{
setBufferValue(i,false);
}
}
//+------------------------------------------------------------------+
//| 2. 過去チャートのインジケータ値は計算済で、
//| 前回計算済Bar数 < チャートの最大Bar数 の場合 (Liveで新規Barが発生した)
//| → 新規Barのインジケータ値を計算する。
//+------------------------------------------------------------------+
else
{
if(prev_calculated < rates_total)
{
setBufferValue(0,true);
}
}
//+------------------------------------------------------------------+
//| 3. 同Bar内でのティック変更によって呼び出された場合
//| → インジケータ値は計算しない
//+------------------------------------------------------------------+
// NOP
//+------------------------------------------------------------------+
//| 今回の処理でインジケータ値を計算したBar数を返却する。
//| → このreturn値は、次回OnCalculate関数が呼び出された際、
//| 引数のprev_calculatedに設定される。
//+------------------------------------------------------------------+
return(rates_total);
}
//+------------------------------------------------------------------+
//| 【インデックスバッファ設定関数】
//| ・指定されたBar位置のインジケータ値を計算する。
//+------------------------------------------------------------------+
void setBufferValue(int iCurrentBar, bool bIsLiveNewBar)
{
// 現在Bar位置に、1つ前のBarの高値をプロットする。
bufHigh[iCurrentBar] = iHigh(Symbol(),PERIOD_CURRENT,iCurrentBar+1);
// Liveで新規Barが発生した場合のみ、Slackでインジケータ値を通知する。
// 過去チャートのインジケータ値を計算している時は通知しない。
if(bIsLiveNewBar)
{
NotifySlack.Notify(DoubleToString(bufHigh[iCurrentBar],5),true);
}
}
//+------------------------------------------------------------------+
コード解説
11行目
Slack通知用クラスのクラスファイルを取り込んでいます。インジケータファイルと同階層に配置する前提のため””で括っていますが、クラスファイルをIncludeフォルダに配置した場合は、<>で括ってください。詳しくは、MQL5の公式サイトのこちらを参照してください。
22行目
Slack通知用クラスのインスタンスを定義しています。クラスの実体を作成しているため、コンストラクタがこのタイミングで動き、Slackとの接続情報がクラスのインスタンスに設定されます。
55~93行目
新規ローソク足発生時のみ計算する処理になっています。解説はこちらの記事を参照してください。
107~113行目
Liveで新規Barが発生した場合のみ、インジケータの値をSlackでメンション付きで通知しています。過去データのインジケータ値算出の際もSlack通知処理を呼び出してしまうと、大量にSlack通知が届いて大変な事になるので注意してください。
実行結果
「Slack通知確認用インジケータ」をチャートに設定する際、下記ダイアログが表示されるので、「DLLの使用を許可する」にチェックをしてください。
「Slack通知確認用インジケータ」を1分足チャートに設定した実行結果です。過去データのインジケータ値算出の際にはSlack通知されず、Liveで新規Barが発生した場合のみ、Slack通知されている事が分かります。
まとめ
今回は、インジケータからSlackに通知する方法を紹介しました。
Slackはビジネスチャットツールなので、単にメッセージを通知するだけではなくて色々なサービス連携機能があります。MT5のシグナルをトリガにして他サービスを起動したり、逆にSlackからコマンドを叩く事によりMT5を操作したり、というような事も出来ますので、面白いネタがあれば記事にしてきたいと思います。
コメント