【コピペでOK】RSIのEAに口座認証や一括メッセージ機能を実装してみました

MQL実装例
yuki
yuki
この記事ではお手本として、シンプルなRSIのEAに、口座認証や一括メッセージ機能、アップデート自動お知らせなどの機能を実装してみました
カオチャイ
カオチャイ
全体コードを個別に分けて解説していきますね!
yuki
yuki
この機能は無料でご利用できますが、MQLAuth.mqhのバージョン1.01以上がインストールされている必要がございますので、まだ準備ができていない方は下記の記事を参考にしてくださいね!
MQLAuth準備編
MQLAuthシステムを利用するための事前準備 MQLAuthを使うための準備 MQLAuthシステムを使う前提条件として「インジケーターをMT4の口座番号やパスワードで縛って管...

個人でEAを販売する際につけておきたい機能たち

MT4チャートチャートにリンク付きのロゴを付けたり、一括メッセージを表示できるEAです

 

今回書いていくコードには下記の4つを実装しています

口座番号認証機能

リンク付き一括メッセージ機能

リンク付き個別メッセージ機能

アップデートお知らせ

リンク付きロゴ

・RSIのEA(20以下で売り全決済、買いポジを持つ/80以上で買い全決済、売りポジを持つ)

 

カオチャイ
カオチャイ
それでは解説していきますが、個別のコード解説の部分にはわかりやすくするために注釈や一部コードを削除しておりますので、コピペで実装を行う場合は、全体コードを利用して下さいね

 

まずはコードの全体像(コピペ用)

//+------------------------------------------------------------------+
//|                                                        RSIEA.mq4 |
//|                                      ©2020  MT4ツール製作【シストレファクトリー】 |
//|                                 https://interactivebrokers.work/ |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|  設定必須項目[MQLAUTH_ID] [APPLICATION_NAME]                      |
//+------------------------------------------------------------------+
#define MQLAUTH_ID ""
#define APPLICATION_NAME ""

#define VERSION "1.00"
#define HTTP_QUERY_FLAG -2147483648
string _prefix = "RSIEA_";
#include <MQLAuth.mqh>
#property copyright "©2020  MT4ツール製作【シストレファクトリー】"
#property link      "https://interactivebrokers.work/"
#property version   VERSION
#property strict

//+------------------------------------------------------------------+
//|  カスタマイズ                                                        |
//+------------------------------------------------------------------+
bool _useApplicationMessage = true; // 一斉メッセージを利用する
int _applicationMessageViewSecond = 8; // メッセージを消すまでの秒数
bool _useUserMessage = true; // 個別メッセージを利用する
int _userMessageViewSecond = 8; // メッセージを消すまでの秒数
bool _useUpdateMessage = true; // アップデートのお知らせを利用する
bool _useLogo = true; // ロゴを表示する
string _logourl = "https://interactivebrokers.work/"; // ロゴをクリックしたときに開くURLを格納する変数
bool _testAuth = true; // バックテスト時も認証をする

//+------------------------------------------------------------------+
//|  グローバル変数                                                     |
//+------------------------------------------------------------------+
//--- 口座認証に利用する変数
bool _isAuthorized = false; // 口座認証の成否を表す変数
datetime _date; // 口座認証を行った時間を保存する変数
string _ObjectAuthMessage1 = _prefix + "objectAuthMessage1"; // 認証メッセージを表示するラベル名1
string _ObjectAuthMessage2 = _prefix + "objectAuthMessage2"; // 認証メッセージを表示するラベル名2
//--- 口座認証に利用する変数

//--- 一斉メッセージに利用する変数
datetime _receiveApplicationMessage; // 前回メッセージを受信した日時
string _applicationMessageurl; // メッセージをクリックしたときに開くURLを格納する変数
string _labelApplicationMessage = _prefix + "applicationMessage"; // メッセージを表示するラベル名
long _viewApplicationMessageTime = 0; // メッセージを表示した日時を格納する変数
//--- 一斉メッセージに利用する変数

//--- 個別メッセージに利用する変数
datetime _receiveUserMessage; // 前回メッセージを受信した日時
string _userMessageurl; // メッセージをクリックしたときに開くURLを格納する変数
string _labelUserMessage = _prefix + "userMessage"; // メッセージを表示するラベル名
long _viewUserMessageTime = 0; // メッセージを表示した日時を格納する変数
//--- 個別メッセージに利用する変数

//--- アップデートのお知らせに利用する変数
string _updateurl; // アップデートのお知らせをクリックしたときに開くURLを格納する変数
string _labelUpdateMessage = _prefix + "updateMessage"; // アップデートのお知らせを表示するラベル名
string _labelUpdateMessage2 = _prefix + "updateMessage2"; // アップデートのお知らせを表示するラベル名
//--- アップデートのお知らせに利用する変数

//--- ロゴに利用する変数
string _objectLogo = _prefix + "LOGO"; // ロゴオブジェクトの名前
//--- ロゴに利用する変数

//+------------------------------------------------------------------+
//|  OnInit                                                          |
//+------------------------------------------------------------------+
int OnInit() {
//--- ストラテジーテスターを使う場合の認証 ---
   if(IsTesting() && _testAuth)
      Auth();
//--- ストラテジーテスターを使う場合の認証 ---

//--- ロゴ表示 ---
   if(_useLogo)
      Auth_ShowIMG(_logo, _objectLogo, 50, 50, 2, 20, 20, 1);
//--- ロゴ表示 ---

//--- タイマー ---
   EventSetTimer(1);
//--- タイマー ---

   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//|   OnDeinit                                                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
//--- タイマー削除 ---
   EventKillTimer();

//--- ラベル削除
   ObjectsDeleteAll(ChartID(), _prefix, EMPTY, EMPTY);
}
//+------------------------------------------------------------------+
//|   OnTimer                                                        |
//+------------------------------------------------------------------+
void OnTimer() {
//--- 口座番号認証 ---
   if(AccountInfoInteger(ACCOUNT_LOGIN) != 0) {
      if(TimeDay(TimeLocal()) != TimeDay(_date)) {
         _date = TimeLocal();
         Auth();
      }
   }
//--- 口座番号認証 ---

//--- メッセージの処理 ---
   Message();
//--- メッセージの処理 ---
}
//+------------------------------------------------------------------+
//|   OnChartEvent                                                   |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam) {
   if(id == CHARTEVENT_OBJECT_CLICK) {
      if(StringFind(sparam, _labelApplicationMessage) >= 0)
         if(_applicationMessageurl != "")
            bool result = Auth_OpenURL(_applicationMessageurl);

      if(StringFind(sparam, _labelUserMessage) >= 0)
         if(_userMessageurl != "")
            bool result = Auth_OpenURL(_userMessageurl);

      if(sparam == _labelUpdateMessage)
         if(_updateurl != "")
            bool result = Auth_OpenURL(_updateurl);

      if(StringFind(sparam,  _objectLogo) >= 0)
         if(_logourl != "")
            bool result = Auth_OpenURL(_logourl);
   }
}
//+------------------------------------------------------------------+
//| OnTick                                                        |
//+------------------------------------------------------------------+
void OnTick() {
   if(!_isAuthorized) return;
   int signal = Signal(0);
   if(PositionCount(0) == 0 && signal > 0) {
      CloseAllPositions(1); // 売りポジションを全決済
      int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 30, 0, 0);
   } else if(PositionCount(1) == 0 && signal < 0) {
      CloseAllPositions(0); // 買いポジションを全決済
      int ticket = OrderSend(Symbol(), OP_SELL, 0.1, Bid, 30, 0, 0);
   }
}
//+------------------------------------------------------------------+
//| RSIが20以下で1、80以上で-1、それ以外は0を返す関数                      |
//+------------------------------------------------------------------+
int Signal(int bar) {
   double rsi = iRSI(Symbol(), PERIOD_CURRENT, 14, PRICE_CLOSE, bar);
   if(rsi <= 20) return 1;
   else if(rsi >= 80) return -1;
   return 0;
}
//+------------------------------------------------------------------+
//| ポジションの数を返す関数(引数0で買いポジションの数、1で売りポジションの数)       |
//+------------------------------------------------------------------+
int PositionCount(int type) {
   int count = 0;
   for(int i = OrdersTotal() - 1; i >= 0; i--) {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) break;
      if(OrderSymbol() != Symbol()) continue;
      if((OrderType() == OP_BUY && type == 0) || (OrderType() == OP_SELL && type == 1)) {
         count++;
      }
   }
   return count;
}
//+------------------------------------------------------------------+
//| 全てのポジションを決済する関数(引数0で買いポジションを決済、1で売りポジションを決済|
//+------------------------------------------------------------------+
void CloseAllPositions(int type) {
   for(int i = OrdersTotal() - 1; i >= 0; i--) {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) break;
      if(OrderSymbol() != Symbol()) continue;
      if(OrderType() == OP_BUY && type == 0) {
         RefreshRates();
         int result = OrderClose(OrderTicket(), OrderLots(), Bid, 30);
      } else if(OrderType() == OP_SELL && type == 1) {
         RefreshRates();
         int result = OrderClose(OrderTicket(), OrderLots(), Ask, 30);
      }
   }
}
//+------------------------------------------------------------------+
//|  口座認証のための関数                                               |
//+------------------------------------------------------------------+
void Auth() {
   datetime period = AuthByAccountNumber_ReturnDatetime(MQLAUTH_ID, APPLICATION_NAME);
   if(period >= TimeLocal()) {
      _isAuthorized = true;
      //--- バージョン情報を確認し、更新がある場合はお知らせを表示する
      if(_useUpdateMessage) {
         string newestVersion = Auth_GetNewestVersion(MQLAUTH_ID, APPLICATION_NAME, _updateurl);
         if(newestVersion != "" && StringToDouble(VERSION) < StringToDouble(newestVersion)) {
            ObjectCreate(ChartID(), _labelUpdateMessage, OBJ_LABEL, 0, 0, 0);
            ObjectSetInteger(ChartID(), _labelUpdateMessage, OBJPROP_SELECTABLE, false);
            ObjectSetInteger(ChartID(), _labelUpdateMessage, OBJPROP_SELECTED, false);
            ObjectSetInteger(ChartID(), _labelUpdateMessage, OBJPROP_HIDDEN, true);
            ObjectSetInteger(ChartID(), _labelUpdateMessage, OBJPROP_CORNER, CORNER_LEFT_LOWER);
            ObjectSetInteger(ChartID(), _labelUpdateMessage, OBJPROP_XDISTANCE, 80);
            ObjectSetInteger(ChartID(), _labelUpdateMessage, OBJPROP_YDISTANCE, 60);
            ObjectSetInteger(ChartID(), _labelUpdateMessage, OBJPROP_ZORDER, 8);
            ObjectSetText(_labelUpdateMessage, "新しいバージョン " + newestVersion + " があります。", 12, "Meiryo", (color)ChartGetInteger(ChartID(), CHART_COLOR_FOREGROUND));
            ObjectCreate(ChartID(), _labelUpdateMessage2, OBJ_LABEL, 0, 0, 0);
            ObjectSetInteger(ChartID(), _labelUpdateMessage2, OBJPROP_SELECTABLE, false);
            ObjectSetInteger(ChartID(), _labelUpdateMessage2, OBJPROP_SELECTED, false);
            ObjectSetInteger(ChartID(), _labelUpdateMessage2, OBJPROP_HIDDEN, true);
            ObjectSetInteger(ChartID(), _labelUpdateMessage2, OBJPROP_CORNER, CORNER_LEFT_LOWER);
            ObjectSetInteger(ChartID(), _labelUpdateMessage2, OBJPROP_XDISTANCE, 80);
            ObjectSetInteger(ChartID(), _labelUpdateMessage2, OBJPROP_YDISTANCE, 40);
            ObjectSetInteger(ChartID(), _labelUpdateMessage2, OBJPROP_ZORDER, 8);
            ObjectSetText(_labelUpdateMessage2, "ダウンロードするにはここをクリック", 12, "Meiryo", (color)ChartGetInteger(ChartID(), CHART_COLOR_FOREGROUND));
         }
      }
      //--- バージョン情報を確認し、更新がある場合はお知らせを表示する
   } else {
      _isAuthorized = false;
      //--- 認証メッセージを表示するラベルの作成 ---
      ObjectCreate(_ObjectAuthMessage1, OBJ_LABEL, 0, 0, 0);
      ObjectSet(_ObjectAuthMessage1, OBJPROP_BACK, false);
      ObjectSetInteger(ChartID(), _ObjectAuthMessage1, OBJPROP_BGCOLOR, clrRed);

      ObjectSet(_ObjectAuthMessage1, OBJPROP_SELECTABLE, false);
      ObjectSet(_ObjectAuthMessage1, OBJPROP_SELECTED, false);
      ObjectSet(_ObjectAuthMessage1, OBJPROP_HIDDEN, true);
      ObjectSet(_ObjectAuthMessage1, OBJPROP_CORNER, CORNER_LEFT_LOWER);
      ObjectSet(_ObjectAuthMessage1, OBJPROP_XDISTANCE, 80);
      ObjectSet(_ObjectAuthMessage1, OBJPROP_YDISTANCE, 48);
      ObjectSetText(_ObjectAuthMessage1, "無料期間が終了しました", 18, "MS ゴシック", (color)ChartGetInteger(ChartID(), CHART_COLOR_FOREGROUND));
      ObjectCreate(_ObjectAuthMessage2, OBJ_LABEL, 0, 0, 0);
      ObjectSet(_ObjectAuthMessage2, OBJPROP_BACK, false);
      ObjectSetInteger(ChartID(), _ObjectAuthMessage2, OBJPROP_BGCOLOR, clrRed);

      ObjectSet(_ObjectAuthMessage2, OBJPROP_SELECTABLE, false);
      ObjectSet(_ObjectAuthMessage2, OBJPROP_SELECTED, false);
      ObjectSet(_ObjectAuthMessage2, OBJPROP_HIDDEN, true);
      ObjectSet(_ObjectAuthMessage2, OBJPROP_CORNER, CORNER_LEFT_LOWER);
      ObjectSet(_ObjectAuthMessage2, OBJPROP_XDISTANCE, 80);
      ObjectSet(_ObjectAuthMessage2, OBJPROP_YDISTANCE, 18);
      ObjectSetText(_ObjectAuthMessage2, "期間を延長する場合は左側のロゴをクリックしてください", 18, "MS ゴシック", (color)ChartGetInteger(ChartID(), CHART_COLOR_FOREGROUND));
//--- 認証メッセージを表示するラベルの作成 ---
   }
}
//+------------------------------------------------------------------+
//|   メッセージを取得し表示する関数                                       |
//+------------------------------------------------------------------+
void Message() {
   if(_isAuthorized && _useApplicationMessage && TimeHour(TimeLocal()) != TimeHour(_receiveApplicationMessage)) {
      _receiveApplicationMessage = TimeLocal();

      string messages = Auth_GetApplicationMessage(MQLAUTH_ID, APPLICATION_NAME);
      if(messages != "") {
         ObjectSetInteger(ChartID(), _labelUpdateMessage, OBJPROP_YDISTANCE, -100);
         ObjectSetInteger(ChartID(), _labelUpdateMessage2, OBJPROP_YDISTANCE, -100);

         if(StringFind(messages, "#", 0) >= 0) {
            string result[];
            StringSplit(messages, '#', result);
            string message[];
            StringSplit(result[0], '\r', message);

            for(int i = 0; i < ArraySize(message); i++) {
               ObjectCreate(ChartID(), _labelApplicationMessage + (string)i, OBJ_LABEL, 0, 0, 0);
               ObjectSetInteger(ChartID(), _labelApplicationMessage + (string)i, OBJPROP_BACK, false);
               ObjectSetInteger(ChartID(), _labelApplicationMessage + (string)i, OBJPROP_SELECTABLE, false);
               ObjectSetInteger(ChartID(), _labelApplicationMessage + (string)i, OBJPROP_SELECTED, false);
               ObjectSetInteger(ChartID(), _labelApplicationMessage + (string)i, OBJPROP_HIDDEN, true);
               ObjectSetInteger(ChartID(), _labelApplicationMessage + (string)i, OBJPROP_CORNER, CORNER_LEFT_LOWER);
               ObjectSetInteger(ChartID(), _labelApplicationMessage + (string)i, OBJPROP_XDISTANCE, 85);
               ObjectSetInteger(ChartID(), _labelApplicationMessage + (string)i, OBJPROP_YDISTANCE, 20 + 20 * (ArraySize(message) - 1 - i));
               ObjectSetText(_labelApplicationMessage + (string)i, message[i], 12, "Meiryo", (color)ChartGetInteger(ChartID(), CHART_COLOR_FOREGROUND));
            }
            _applicationMessageurl = result[1];
         } else {
            string message[];
            StringSplit(messages, '\r', message);

            for(int i = 0; i < ArraySize(message); i++) {
               ObjectCreate(ChartID(), _labelApplicationMessage + (string)i, OBJ_LABEL, 0, 0, 0);
               ObjectSetInteger(ChartID(), _labelApplicationMessage + (string)i, OBJPROP_BACK, false);
               ObjectSetInteger(ChartID(), _labelApplicationMessage + (string)i, OBJPROP_SELECTABLE, false);
               ObjectSetInteger(ChartID(), _labelApplicationMessage + (string)i, OBJPROP_SELECTED, false);
               ObjectSetInteger(ChartID(), _labelApplicationMessage + (string)i, OBJPROP_HIDDEN, true);
               ObjectSetInteger(ChartID(), _labelApplicationMessage + (string)i, OBJPROP_CORNER, CORNER_LEFT_LOWER);
               ObjectSetInteger(ChartID(), _labelApplicationMessage + (string)i, OBJPROP_XDISTANCE, 85);
               ObjectSetInteger(ChartID(), _labelApplicationMessage + (string)i, OBJPROP_YDISTANCE, 30 + 20 * (ArraySize(message) - 1 - i));
               ObjectSetText(_labelApplicationMessage + (string)i, message[i], 12, "Meiryo", (color)ChartGetInteger(ChartID(), CHART_COLOR_FOREGROUND));
            }
            _applicationMessageurl = "";
         }
         _viewApplicationMessageTime = GetTickCount();
      }
   }
   if(_isAuthorized && _useUserMessage && GetTickCount() - _viewApplicationMessageTime > _applicationMessageViewSecond * 1000 && TimeHour(TimeLocal()) !=  TimeHour(_receiveUserMessage)) {
      _receiveUserMessage = TimeLocal();
      ObjectsDeleteAll(ChartID(), _labelApplicationMessage, EMPTY, EMPTY);

      string messages = Auth_GetUserMessageByAccountNumber(MQLAUTH_ID, APPLICATION_NAME);
      if(messages != "") {
         ObjectSetInteger(ChartID(), _labelUpdateMessage, OBJPROP_YDISTANCE, -100);
         ObjectSetInteger(ChartID(), _labelUpdateMessage2, OBJPROP_YDISTANCE, -100);

         if(StringFind(messages, "#", 0) >= 0) {
            string result[];
            StringSplit(messages, '#', result);
            string message[];
            StringSplit(result[0], '\r', message);

            for(int i = 0; i < ArraySize(message); i++) {
               ObjectCreate(ChartID(), _labelUserMessage + (string)i, OBJ_LABEL, 0, 0, 0);
               ObjectSetInteger(ChartID(), _labelUserMessage + (string)i, OBJPROP_BACK, false);
               ObjectSetInteger(ChartID(), _labelUserMessage + (string)i, OBJPROP_SELECTABLE, false);
               ObjectSetInteger(ChartID(), _labelUserMessage + (string)i, OBJPROP_SELECTED, false);
               ObjectSetInteger(ChartID(), _labelUserMessage + (string)i, OBJPROP_HIDDEN, true);
               ObjectSetInteger(ChartID(), _labelUserMessage + (string)i, OBJPROP_CORNER, CORNER_LEFT_LOWER);
               ObjectSetInteger(ChartID(), _labelUserMessage + (string)i, OBJPROP_XDISTANCE, 85);
               ObjectSetInteger(ChartID(), _labelUserMessage + (string)i, OBJPROP_YDISTANCE, 20 + 20 * (ArraySize(message) - 1 - i));
               ObjectSetText(_labelUserMessage + (string)i, message[i], 12, "Meiryo", (color)ChartGetInteger(ChartID(), CHART_COLOR_FOREGROUND));
            }
            _userMessageurl = result[1];
         } else {
            string message[];
            StringSplit(messages, '\r', message);

            for(int i = 0; i < ArraySize(message); i++) {
               ObjectCreate(ChartID(), _labelUserMessage + (string)i, OBJ_LABEL, 0, 0, 0);
               ObjectSetInteger(ChartID(), _labelUserMessage + (string)i, OBJPROP_BACK, false);
               ObjectSetInteger(ChartID(), _labelUserMessage + (string)i, OBJPROP_SELECTABLE, false);
               ObjectSetInteger(ChartID(), _labelUserMessage + (string)i, OBJPROP_SELECTED, false);
               ObjectSetInteger(ChartID(), _labelUserMessage + (string)i, OBJPROP_HIDDEN, true);
               ObjectSetInteger(ChartID(), _labelUserMessage + (string)i, OBJPROP_CORNER, CORNER_LEFT_LOWER);
               ObjectSetInteger(ChartID(), _labelUserMessage + (string)i, OBJPROP_XDISTANCE, 85);
               ObjectSetInteger(ChartID(), _labelUserMessage + (string)i, OBJPROP_YDISTANCE, 30 + 20 * (ArraySize(message) - 1 - i));
               ObjectSetText(_labelUserMessage + (string)i, message[i], 12, "Meiryo", (color)ChartGetInteger(ChartID(), CHART_COLOR_FOREGROUND));
            }
            _userMessageurl = "";
         }
         _viewUserMessageTime = GetTickCount();
      }
   }
   if(_useUserMessage && _viewUserMessageTime != 0 && GetTickCount() - _viewUserMessageTime > _userMessageViewSecond * 1000) {
      ObjectsDeleteAll(ChartID(), _labelUserMessage, EMPTY, EMPTY);
      ObjectSetInteger(ChartID(), _labelUpdateMessage, OBJPROP_YDISTANCE, 60);
      ObjectSetInteger(ChartID(), _labelUpdateMessage2, OBJPROP_YDISTANCE, 40);
   } else if(!_useUserMessage && _viewApplicationMessageTime != 0 && GetTickCount() - _viewApplicationMessageTime > _applicationMessageViewSecond * 1000) {
      ObjectsDeleteAll(ChartID(), _labelApplicationMessage, EMPTY, EMPTY);
      ObjectSetInteger(ChartID(), _labelUpdateMessage, OBJPROP_YDISTANCE, 60);
      ObjectSetInteger(ChartID(), _labelUpdateMessage2, OBJPROP_YDISTANCE, 40);
   }
}
//+------------------------------------------------------------------+
//|   ロゴ画像データ                                                    |
//+------------------------------------------------------------------+
int _logo[] = { 省略 };

 

カオチャイ
カオチャイ
このコードはこちらからダウンロードできます!
yuki
yuki
そのまま利用するためには下記の部分を書き換える必要がありますのでご注意くださいね!

#define MQLAUTH_ID “” //””内に自分のMQLAUTH_IDを記入する

#define APPLICATION_NAME “” // “”内に自分の登録したEA・インジケーター名に書き換える(※ユーザー名ではないので注意)

 

カオチャイ
カオチャイ
というわけで、個別の解説にいきたいと思います!

 

コードの解説

一斉メッセージを利用する設定

//+------------------------------------------------------------------+
//|  カスタマイズ                                                        |
//+------------------------------------------------------------------+
bool _useApplicationMessage = true; // 一斉メッセージを利用する
int _applicationMessageViewSecond = 8; // メッセージを消すまでの秒数

_useApplicationMessageにtrueを設定すると、MQLAuthで設定した一斉メッセージが表示されるようになります。一斉メッセージを利用しない場合はfalseに設定してください。

一斉メッセージは設定した秒数の間表示されます。デフォルトでは8秒になっていますので、必要に応じて調整してください。

 

個別メッセージを利用する設定

//+------------------------------------------------------------------+
//|  カスタマイズ                                                        |
//+------------------------------------------------------------------+
bool _useUserMessage = true; // 個別メッセージを利用する
int _userMessageViewSecond = 8; // メッセージを消すまでの秒数

_useUserMessageにtrueを設定すると、MQLAuthで設定した個別メッセージが表示されるようになります。個別メッセージを利用しない場合はfalseに設定してください。

個別メッセージは設定した秒数の間表示されます。デフォルトでは8秒になっていますので、必要に応じて調整してください。

 

アップデートのお知らせを利用する設定

//+------------------------------------------------------------------+
//|  カスタマイズ                                                        |
//+------------------------------------------------------------------+
bool _useUpdateMessage = true; // アップデートのお知らせを利用する

_useUpdateMessageにtrueを設定すると、MQLAuthで設定したバージョン番号が現在のバージョン番号より大きい場合にアップデートのお知らせが表示されるようになります。アップデートのお知らせを利用しない場合はfalseに設定してください。

アップデートのお知らせは、アップデートされるまではずっと表示されたままになります。

 

ロゴを利用する設定

//+------------------------------------------------------------------+
//|  カスタマイズ                                                        |
//+------------------------------------------------------------------+
bool _useLogo = true; // ロゴを表示する

_useLogoにtrueを設定すると、チャート画面左下にロゴが表示されるようになります。ロゴを表示しない場合はfalseに設定してください。

//+------------------------------------------------------------------+
//|   ロゴデータ                                          |
//+------------------------------------------------------------------+
int _logo[] = { 省略 };

ロゴを表示するには、ロゴ画像のデータをあらかじめソースコードに書いておく必要があります。ロゴ画像をソースコードに書く方法については以下の記事を参考にしてください。

MT4に画像を表示
MT4のチャート上に画像を表示してみよう https://interactivebrokers.work/start_mqlauth/ MT4に画像を表示 こ...
//+------------------------------------------------------------------+
//|  カスタマイズ                                                        |
//+------------------------------------------------------------------+
string _logourl = "https://interactivebrokers.work/"; // ロゴをクリックしたときに開くURLを格納する変数

ロゴをクリックしたときに開くサイトのURLを変更する場合は、変数_logourlに設定します。

 

バックテスト時も認証をする設定

//+------------------------------------------------------------------+
//|  カスタマイズ                                                        |
//+------------------------------------------------------------------+
bool _testAuth = true; // バックテスト時も認証をする

_testAuthにtrueを設定すると、バックテスト時にも口座番号認証が行われ、口座番号が違うMT4だとバックテストができなくなります。

リアルタイムチャートでは口座番号縛りをしたいけど、バックテストはどの口座番号でもできるようにする場合はfalseに設定してください。

 

RSIのEA(20以下で売り全決済、買いポジを持つ/80以上で買い全決済、売りポジを持つ)

RSI20以下で買い、80以上で売るロジックです。ポジションは1つしか持たず、買いシグナルで売り決済、売りシグナルで買い決済(ドテン)するので常にポジションを持ったままになります。売買を行うロジックは、以下の4つの場所に分かれています。

//+------------------------------------------------------------------+
//| RSIが20以下で1、80以上で-1、それ以外は0を返す関数                 |
//+------------------------------------------------------------------+
int Signal(int bar) {
   double rsi = iRSI(Symbol(), PERIOD_CURRENT, 14, PRICE_CLOSE, bar);
   if(rsi <= 20) return 1;
   else if(rsi >= 80) return -1;
   return 0;
}

売買条件に一致しているかどうかの判定をしている関数です。RSIが20以下のときに1を返し、80以上のときに-1を返し、それ以外は0を返しています。

//+------------------------------------------------------------------+
//|   OnTick                                                         |
//+------------------------------------------------------------------+
void OnTick() {
   if(!_isAuthorized) return;

   int signal = Signal(0);
   if(PositionCount(0) == 0 && signal > 0) {
      CloseAllPositions(1); // 売りポジションを全決済
      int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 30, 0, 0);
   } else if(PositionCount(1) == 0 && signal < 0) {
      CloseAllPositions(0); // 買いポジションを全決済
      int ticket = OrderSend(Symbol(), OP_SELL, 0.1, Bid, 30, 0, 0);
   }
}

OnTick関数内では、前述のSignal関数で返された結果をもとに、ローソク足毎に売買判定を行っています。買い判定のときは売りポジションを全決済し買いポジションを持ち、売り判定のときは買いポジションを全決済し売りポジションを持ちます。

//+------------------------------------------------------------------+
//| ポジションの数を返す関数(引数0で買いポジションの数、1で売りポジションの数)       |
//+------------------------------------------------------------------+
int PositionCount(int type) {
   int count = 0;
   for(int i = OrdersTotal() - 1; i >= 0; i--) {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) break;
      if(OrderSymbol() != Symbol()) continue;
      if((OrderType() == OP_BUY && type == 0) || (OrderType() == OP_SELL && type == 1)) {
         count++;
      }
   }
   return count;
}

ポジションの総数を返す関数です。ポジションをいくつ持っているかをこの関数を利用して取得します。

//+------------------------------------------------------------------+
//| 全てのポジションを決済する関数(引数0で買いポジションを決済、1で売りポジションを決済|
//+------------------------------------------------------------------+
void CloseAllPositions(int type) {
   for(int i = OrdersTotal() - 1; i >= 0; i--) {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) break;
      if(OrderSymbol() != Symbol()) continue;
      if(OrderType() == OP_BUY && type == 0) {
         RefreshRates();
         int result = OrderClose(OrderTicket(), OrderLots(), Bid, 30);
      } else if(OrderType() == OP_SELL && type == 1) {
         RefreshRates();
         int result = OrderClose(OrderTicket(), OrderLots(), Ask, 30);
      }
   }
}

買いポジションまたは売りポジションを全て決済するための関数です。

ロジックをオリジナルのものに書き換えるときは、この4か所を見て、書き換えればよいでしょう。

 

yuki
yuki
解説は以上となります。他の応用編に関しては下記の記事を参考にしてくださいね、お疲れさまでした!
EAやインジケーターに認証をつける方法
MT4のEAやインジケーターにサーバー認証(口座番号縛り)を実装する方法MQLAuthを使って、EAやインジケーターに口座番号認証を実装する方法を紹介しています。 従来のコピー防止だけでなく、遠隔での停止や決済機能の自動化なども可能になる画期的な認証方法です。...
MQL実装例
【コピペでOK】MT4のチャートから飛ばすURLをソースコードを編集せずに、MQLAuthの管理画面から変えられるようにする https://interactivebrokers.work/start_mqlauth/ メッセージのURL変更を簡単に ...
MQL実装例
【コピペでOK】バイナリーオプションサインツールに体験版機能を機能を実装してみました https://interactivebrokers.work/start_mqlauth/ 体験版機能付きのBO用サインツー...