English Русский 中文 Español Deutsch Português
取引イベントおよびシグナルの音声通知システム

取引イベントおよびシグナルの音声通知システム

MetaTrader 5 | 16 11月 2020, 09:10
690 0
Alexander Fedosov
Alexander Fedosov

目次

はじめに

MetaTrader 5取引ターミナルは、音声アラートの使用を可能にするオプションを備えています。11のイベントに対して、個別の音声アラートを割り当てることができます。ただし、取引システムのシグナルの出現や、ポジションを開く、決済する、変更するなどのエキスパートアドバイザーのアクションなど、ユーザが音声通知を受信する必要がある状況はさらに多くあります。今日では、ナビゲーター、音声検索、翻訳ツールがよく使用され、音声アシスタントは人間の生活において重要な役割を果たしています。このアイデアは、MetaTrader5ターミナルで取引するときに使用できます。本稿では、さまざまな取引イベント、市場の状態、取引シグナルによって生成されるシグナルに対するシンプルでユーザフレンドリーな音声通知システムの開発を試みます。


音声通知システムの開発

システムの作成を開始する前に付け加えたいのですが、音声通知を実装するために選択したイベントは、デモ目的のみで選択されています。このセットでは不十分な場合は、独自のイベントと関連する音声アラートを追加してください。本稿をお読みになれば、MQL5に関する幅広い知識がなくても、システムの拡張とカスタマイズは非常に簡単です。

このシステムは、インクルードファイルでCSoundsLibクラスとして実装されます。MQL5/Includeフォルダを開いてSoundsLibフォルダを作成し、中にSoundsLib.mqhファイルを作成してください。クラスを作成する前に、音声アラートの操作にさらに使用される2つの列挙を紹介しましょう。1番目は、アラート言語の選択に使用されるLANGUAGEです。英語とロシア語の2つの言語をサポートします。

//+------------------------------------------------------------------+
//| Enumeration for switching the notification language              |
//+------------------------------------------------------------------+
enum LANGUAGE
{
   RUSSIAN,       // Russian
   ENGLISH        // English
};

2番目の列挙体には、デモ目的で選択した一連のイベントが含まれています。さらに本稿では、指標、エキスパートアドバイザー、クイック取引ツールキットなど、さまざまな既製のシステムにそれらを組み込む方法を示します。列挙体はMESSAGEと呼ばれています。

//+------------------------------------------------------------------+
//| List of voice alerts                                             |
//+------------------------------------------------------------------+
enum MESSAGE
{
   STATUS_ON,                          // Status of enabled voice alerts
   SIGNAL_BUY,                         // A Buy signal
   SIGNAL_SELL,                        // A Sell signal
   BUY_ORDER_SET,                      // A Buy order has been placed
   SELL_ORDER_SET,                     // A Sell order has been placed
   BUYLIMIT_ORDER_SET,                 // A Limit Buy order has been placed
   BUYSTOP_ORDER_SET,                  // A Stop Buy order has been placed
   SELLLIMIT_ORDER_SET,                // A Limit Sell order has been placed
   SELLSTOP_ORDER_SET,                 // A Stop Sell order has been placed
   BUYLIMIT_ORDER_DELETE,              // A Limit Buy order has been deleted
   BUYSTOP_ORDER_DELETE,               // A Stop Buy order has been deleted
   SELLLIMIT_ORDER_DELETE,             // A Limit Sell order has been deleted
   SELLSTOP_ORDER_DELETE,              // A Stop Sell order has been deleted
   BUY_ORDER_CLOSE_PROFIT,             // A Buy order has closed with a profit
   BUY_ORDER_CLOSE_LOSS,               // A Buy order has closed with a loss
   SELL_ORDER_CLOSE_PROFIT,            // A Sell order has closed with a profit
   SELL_ORDER_CLOSE_LOSS,              // A Sell order has closed with a loss
   BUY_ORDER_CLOSE_TP,                 // A Buy order has been closed by Take Profit
   BUY_ORDER_CLOSE_SL,                 // A Buy order has been closed by Stop Loss
   SELL_ORDER_CLOSE_TP,                // A Sell order has been closed by Take Profit
   SELL_ORDER_CLOSE_SL,                // A Sell order has been closed by Stop Loss
   MARKET_CLOSE,                       // Market is closed
   AUTO_TRADING_ON,                    // Automated trading is allowed
   AUTO_TRADING_OFF,                   // Automated trading is prohibited
};

基本セットには24個のアラートが含まれています。それらのほとんどは、ポジションと未決注文の操作とステータスに関連しています。一部のアラートは取引環境の通知に使用されます。最後の3つの通知は、一般的なイベントに関連しています。有効な音声アラートシステムのステータスに関する通知、および買いシグナルまたは売りシグナルの出現に関する通知は、手動または半自動の取引エキスパートアドバイザーを使用する場合、または単純な指標や取引戦略の一部として利用可能な指標を使用する場合に便利です。

CSoundsLibクラスを作成して、作業に必要なメソッドを追加しましょう。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CSoundsLib
{
private:
   LANGUAGE          m_language;
   bool              m_activity_status;
public:
                     CSoundsLib(void); 
                    ~CSoundsLib(void);
   //--- Set the notification language
   void              Language(LANGUAGE lang);
   //--- Set/get the status of the voice alerts system
   void              IsActive(bool flag);
   bool              IsActive(void);
   //--- Play the specified notification
   bool              Message(MESSAGE msg);
};

privateセクションには2つのアラート(m_language and m_activity_status)があります。これらは、Language()メソッドとIsActive()メソッドで必要です。そのため、音声アラートの言語を設定したり、システムアクティビティステータスを取得/設定したりするために使用されます。上記のアラートの実装は次のとおりです。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CSoundsLib::Language(LANGUAGE lang)
{
   m_language=lang;
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CSoundsLib::IsActive(void)
{
   return(m_activity_status);
}

後1つのメソッドはMessage()です。これは、MESSAGE列挙から選択された通知を再生します。 このメソッドの実装も理解しやすいです。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool  CSoundsLib::Message(MESSAGE msg)
{
   if(!m_activity_status)
      return(false);
   string name=(m_language==RUSSIAN ? EnumToString(msg)+"_RU" : EnumToString(msg)+"_EN");
   if(PlaySound("\\Files\\SoundsLib\\"+name+".wav"))
      return(true);
   else
   {
      if(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian")
         Print("Файл не найден");
      else
         Print("File not found");
      return(false);
   }
}

次の重要な点に注意してください。これらは、独自の音声通知を追加してシステムをさらに正しく拡張するのに役立ちます。1番目の点は、音声ファイルを保存する正しい場所です。デフォルトでは、音声ファイルは MQL5/Files/SoundsLibフォルダにあります。SoundsLibフォルダを作成してください。2番目は、作成したフォルダで適切な名前と音声ファイル形式を設定することです。これらのコード行に注意してください。ここでは、_RUまたは_ENサフィックスがMESSAGE型の列挙に追加されます。そのため、たとえば、買いシグナルアラートSIGNAL_BUYに対応するファイル名は、ロシア語と英語の音声アラートの2つの音声ファイル(SIGNAL_BUY_RUとSIGNAL_BUY_EN)に関連付けられます。また、システム関数PlaySound()は*.WAV形式のファイルしか再生できないため、 SoundsLibフォルダでの拡張子付きの完全なファイル名は、次のようになります。

図1 音声ファイルの完全な名前と拡張子

したがって、MESSAGE列挙の24のイベントのセットに対して48の音声ファイルがあります。イベントごとに異なる言語の2つのファイルです。次に、音声アラートを作成するための独自の方法を示します。それでも、任意の方法を使用できます。この記事では、テキストを音声に変換するために無料サービスを使用しました。

図2 テキストを音声に変換するサービス

このサービスは、必要なタスクを実装するための優れた機能を提供します。言語、および必要な形式のタイプを選択できます。ただし、WAV形式は英語ではサポートされていません。ここでは、オンラインコンバーターまたはその他のソフトウェアを使用してmp3をwavに変換できます。システムに必要なすべてのファイルを準備し、MESSAGE列挙と言語サフィックスに従って正しい形式と名前でMQL5\Files\SoundsLibフォルダに保存しました。結果のリストは次のとおりです。

図3 音声アラート用の音声ファイルの完全なリスト

以下は、独自の音声通知を作成する方法の手順を追ったガイドです。

手順1:音声イベントをシステムに追加します。

SoundsLib.mqhファイルを開いて、MESSAGE列挙体を見つけます。意味のある名前でイベントを追加します。命名例を図3と上記のコードに示します。

手順2: 音声アラート用の音声ファイルを作成します。

サービスに移動して(好きなサービスを利用できます)、必要なパラメータを構成し(図2を参照)、言語に応じて「MESSAGE列挙のイベント名」+ _RU(_EN)という名前のMQL5\Files\SoundsLibの下にWAV形式でファイルを保存します。すべての手順が正しく完了すると、新しい音声ファイルは手順1で追加された新しいイベントにリンクされ、使用できるようになります。


指標での実用的な適用

次に、さまざまな例を使用して、それがどのように機能するかを見てみましょう。以下の表で説明されている2つの指標シグナルに基づいて複合指標を作成しましょう。

パラメータ 説明
使用される指標 ADXCloud
使用される指標 ColorZerolagRVI
時間枠の選択 任意
買いの条件 ADXCloudクラウドが緑で、ColorZerolagRVIクラウドが赤から緑のゾーンに移動する
売りの条件 ADXCloudクラウドが緑で、ColorZerolagRVIクラウドが赤から緑に移動する

指標シグナルに基づくエントリの例を図4に示します。これらは、非常に単純です。チャート上に矢印として市場エントリポイントを表示する複合シグナル指標を作成するための基礎として使用します。 

図4 指標シグナルによるエントリ条件

//+------------------------------------------------------------------+
//|                                                      Example.mq5 |
//|                                                         Alex2356 |
//|                           https://www.mql5.com/en/users/alex2356 |
//+------------------------------------------------------------------+
#property copyright "Alex2356"
#property link      "https://www.mql5.com/en/users/alex2356"
#property version   "1.00"
#property indicator_chart_window
//--- two buffers are used for calculating and drawing the indicator
#property indicator_buffers 2
//--- used graphic constructions
#property indicator_plots   2
#property indicator_label1  "Buy Signal"
#property indicator_type1   DRAW_ARROW
//---
#property indicator_label2  "Sell Signal"
#property indicator_type2   DRAW_ARROW
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
input group "ADX Cloud Parameters"
input int                  ADXPeriod         =  8;
input double               Alpha1            =  0.25;
input double               Alpha2            =  0.25;
input group "RVI Color Parameters"
input uint                 Smoothing         =  15;
//----
input double               Weight1           =  0.05;
input int                  RVI_period1       =  8;
//----
input double               Weight2           = 0.10;
input int                  RVI_period2       =   21;
//----
input double               Weight3           = 0.16;
input int                  RVI_period3       =   34;
//----
input double               Weight4           = 0.26;
input int                  RVI_period4       =   55;
//----
input double               Weight5           = 0.43;
input int                  RVI_period5       =   89;
//---
double BuySignal[],SellSignal[],ADXCloud[],FastRVI[],SlowRVI[];
int ADX_Handle,RVI_Hadnle,min_rates_total;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
//---
   SetIndexBuffer(0,BuySignal,INDICATOR_DATA);
   SetIndexBuffer(1,SellSignal,INDICATOR_DATA);
//---
   PlotIndexSetInteger(0,PLOT_ARROW,233);
   PlotIndexSetInteger(1,PLOT_ARROW,234);
//---
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,clrDodgerBlue);
   PlotIndexSetInteger(1,PLOT_LINE_COLOR,clrCrimson);
//---
   ArraySetAsSeries(SellSignal,true);
   ArraySetAsSeries(BuySignal,true);
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,EMPTY_VALUE);
   PlotIndexSetInteger(0,PLOT_ARROW_SHIFT,20);
   PlotIndexSetInteger(1,PLOT_ARROW_SHIFT,-20);
//---
   ADX_Handle=iCustom(Symbol(),PERIOD_CURRENT,"adxcloud",ADXPeriod,Alpha1,Alpha2);
   if(ADX_Handle==INVALID_HANDLE)
   {
      Print(" Failed to create indicator handle");
      return(INIT_FAILED);
   }
//---
   RVI_Hadnle=iCustom(Symbol(),PERIOD_CURRENT,"colorzerolagrvi",
                      Smoothing,
                      Weight1,RVI_period1,
                      Weight2,RVI_period2,
                      Weight3,RVI_period3,
                      Weight4,RVI_period4,
                      Weight5,RVI_period5
                     );
   if(RVI_Hadnle==INVALID_HANDLE)
   {
      Print(" Failed to create indicator handle");
      return(INIT_FAILED);
   }
//---
   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[])
{
//--- c
   if(BarsCalculated(ADX_Handle)<rates_total || BarsCalculated(RVI_Hadnle)<rates_total || rates_total<min_rates_total)
      return(0);
//--- 
   int limit,to_copy,i;
//--- 
   ArraySetAsSeries(ADXCloud,true);
   ArraySetAsSeries(FastRVI,true);
   ArraySetAsSeries(SlowRVI,true);
   ArraySetAsSeries(high,true);
   ArraySetAsSeries(low,true);
//--- 
   if(prev_calculated>rates_total || prev_calculated<=0) 
      limit=rates_total-2;
   else
      limit=rates_total-prev_calculated; 
   to_copy=limit+2;
//---
   if(CopyBuffer(ADX_Handle,0,0,to_copy,ADXCloud)<=0)
      return(0);
//---
   if(CopyBuffer(RVI_Hadnle,0,0,to_copy,FastRVI)<=0)
      return(0);
   if(CopyBuffer(RVI_Hadnle,1,0,to_copy,SlowRVI)<=0)
      return(0);
//--- 
   for(i=limit-1; i>=0 && !IsStopped(); i--)
   {
      if(ADXCloud[i+1]>0 && FastRVI[i+1]>SlowRVI[i+1] && FastRVI[i+2]<SlowRVI[i+2])
      {
         BuySignal[i]=low[i];
         SellSignal[i]=EMPTY_VALUE;
      }
      else if(ADXCloud[i+1]<0 && FastRVI[i+1]<SlowRVI[i+1] && FastRVI[i+2]>SlowRVI[i+2])
      {
         SellSignal[i]=high[i];
         BuySignal[i]=EMPTY_VALUE;
      }
      else
      {
         BuySignal[i]=EMPTY_VALUE;
         SellSignal[i]=EMPTY_VALUE;
      }
   }
//--- return value of prev_calculated for the next call
   return(rates_total);
}
//+------------------------------------------------------------------+

結果の実装を図5に示します。次に、音声通知のシステムを実装する必要があります。

図5 2つの指標に基づく矢印指標

まず、SoundsLib.mqhファイルを指標とリンクします。

#include <SoundsLib/SoundsLib.mqh>

音声通知クラスのインスタンスを作成します。

CSoundsLib Notify;

OnInit()初期化関数で、通知言語を設定します。ここでは英語にします。実際には、英語はデフォルトで設定されているため、追加で設定する必要はありません。ここでの設定は、デモ目的です。

Notify.Language(ENGLISH);

矢印指標は市場のエントリポイントまたは売買シグナルのみを表示するため、MESSAGE列挙からの2つの音声通知を使用します。 

   SIGNAL_BUY,                         // A Buy signal
   SIGNAL_SELL,                        // A Sell signal

通知システムを指標に組み込む場合、アラートは履歴全体で生成されるのではなく、現在のバーでのみ生成されます。したがって、シグナル検索ループを次のように変更します。

//--- 
   for(i=limit-1; i>=0 && !IsStopped(); i--)
   {
      if(ADXCloud[i+1]>0 && FastRVI[i+1]>SlowRVI[i+1] && FastRVI[i+2]<SlowRVI[i+2])
      {
         BuySignal[i]=low[i];
         SellSignal[i]=EMPTY_VALUE;
         if(i==0)
            Notify.Message(SIGNAL_BUY);
      }
      else if(ADXCloud[i+1]<0 && FastRVI[i+1]<SlowRVI[i+1] && FastRVI[i+2]>SlowRVI[i+2])
      {
         SellSignal[i]=high[i];
         BuySignal[i]=EMPTY_VALUE;
         if(i==0)
            Notify.Message(SIGNAL_SELL);
      }
      else
      {
         BuySignal[i]=EMPTY_VALUE;
         SellSignal[i]=EMPTY_VALUE;
      }
   }

ここでは、ゼロバーにシグナルがあるかどうかを確認し、ある場合は、ターミナルユーザに通知します。 


取引エキスパートアドバイザーでの実用的な適用

通常、指標には2種類の音声アラートで十分です。さらに、アラートを実装して、オシレータの買われ過ぎゾーンに入る値、ボリンジャーバンドのチャネルブレイクアウトなどについて通知することができます。エキスパートアドバイザーでは、さらに多くのアラートを使用できます。それでは、市場へのエントリシグナルについて通知するだけでなく、どのポジションタイプが開かれているかなどのさらなるアクションについてもコメントするテスト自動売買ロボットを作成しましょう。まず、エキスパートアドバイザーのエントリ戦略を定義しましょう。 

パラメータ 説明
使用される指標 ColorStDev
使用される指標 3つのTironeレベル
時間枠の選択 任意
買いの条件 ColorStdDevヒストグラムは赤(強い動向)で、現在の価格がTironeの上限レベルよりも高い
売りの条件 ColorStdDevヒストグラムは赤(強い動向)で、現在の価格がTironeの下限レベルよりも低い
エグジット条件   テイクプロフィット/ストップロス

市場へのエントリポイントは図6にあるように表示されます。

図6 この戦略での市場へのエントリの例

MetaTrader 5向けに戦略を実装しましょう。一部のイベントでは音声アラートが使用されます。 

//+------------------------------------------------------------------+
//|                                                  VoiceNotify.mq5 |
//|                                                         Alex2356 |
//|                           https://www.mql5.com/en/users/alex2356 |
//+------------------------------------------------------------------+
#property copyright "Alex2356"
#property link      "https://www.mql5.com/en/users/alex2356"
#property version   "1.00"
#include <SoundsLib/SoundsLib.mqh>
#include <DoEasy25/Engine.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
input uint                 InpStopLoss          =  150;              // Stop Loss, in pips
input uint                 InpTakeProfit        =  250;              // Take Profit, in pips
input double               InpLot               =  0.1;              // Take Profit, in pips
input ulong                InpDeviation         =  10;               // Deviation
input int                  InpMagic             =  2356;             // Magic number
input LANGUAGE             NotifyLanguage       =  ENGLISH;          // Notification Language
//--- ColorStDev indicator parameters
input int                  StDevPeriod          =  12;               // Smoothing period StDev
input ENUM_MA_METHOD       MA_Method            =  MODE_EMA;         // Histogram smoothing method
input ENUM_APPLIED_PRICE   applied_price        =  PRICE_CLOSE;      // Applied price
input int                  MaxTrendLevel        =  90;               // Maximum trend level
input int                  MiddLeTrendLevel     =  50;               // Middle trend level
input int                  FlatLevel            =  20;               // Flat level
//--- Tirone Levels indicator parameters
input int                  TironePeriod         =  13;               // Tirone Period
//---
CEngine trade;
CSoundsLib notify;
int Handle1,Handle2;
double stdev[],tirone_b[],tirone_s[];
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()


{
//---
   if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
      notify.Message(AUTO_TRADING_OFF);
//---
   OnInitTrading();
//--- Get the handle of the ColorStDev indicator
   Handle1=iCustom(Symbol(),PERIOD_CURRENT,"ArticleVoiceNotify\\colorstddev",
                   StDevPeriod,
                   MA_Method,
                   applied_price,
                   MaxTrendLevel,
                   MiddLeTrendLevel,
                   FlatLevel
                  );
   if(Handle1==INVALID_HANDLE)
   {
      Print("Failed to get colorstddev handle");
      Print("Handle = ",Handle1,"  error = ",GetLastError());
      return(INIT_FAILED);
   }
//--- Getting the handle of the Tirone Levels indicator
   Handle2=iCustom(Symbol(),PERIOD_CURRENT,"ArticleVoiceNotify\\tirone_levels_x3",TironePeriod,0);
   if(Handle2==INVALID_HANDLE)
   {
      Print("Failed to get Tirone Levels handle");
      Print("Handle = ",Handle2,"  error = ",GetLastError());
      return(INIT_FAILED);
   }
//---
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
//--- If there are no market positions
   if(ExistPositions(Symbol(),-1,InpMagic)<1)
   {
      //--- Getting data for calculations
      if(!GetIndValue())
         return;
      //--- Open an order if there is a buy signal
      if(BuySignal())
      {
         notify.Message(SIGNAL_BUY);
         if(trade.OpenBuy(InpLot,Symbol(),InpMagic,InpStopLoss,InpTakeProfit))
         {
            Sleep(1400);
            notify.Message(BUY_ORDER_SET);
         }
      }
      //--- Opening an order if there is a sell signal
      if(SellSignal())
      {
         notify.Message(SIGNAL_SELL);
         if(trade.OpenSell(InpLot,Symbol(),InpMagic,InpStopLoss,InpTakeProfit))
         {
            Sleep(1400);
            notify.Message(SELL_ORDER_SET);
         }
      }
   }
}
//+------------------------------------------------------------------+
//| Buy conditions                                                   |
//+------------------------------------------------------------------+
bool BuySignal()
{
   return(tirone_b[1]>iClose(Symbol(),PERIOD_CURRENT,1) && stdev[0]>FlatLevel)?true:false;
}
//+------------------------------------------------------------------+
//| Sell conditions                                                  |
//+------------------------------------------------------------------+
bool SellSignal()
{
   return(tirone_b[1]<iClose(Symbol(),PERIOD_CURRENT,1) && stdev[0]>FlatLevel)?true:false;
}
//+------------------------------------------------------------------+
//| Getting the current values of indicators                         |
//+------------------------------------------------------------------+
bool GetIndValue()
{
   return(CopyBuffer(Handle1,0,0,2,stdev)<=0    ||
          CopyBuffer(Handle2,0,0,2,tirone_b)<=0 ||
          CopyBuffer(Handle2,2,0,2,tirone_s)<=0
         )?false:true;
}
//+----------------------------------------------------------------------------+
//|  Returns the number of open orders                                         |
//+----------------------------------------------------------------------------+
//|  Parameters:                                                               |
//|    op - operation                  (-1   - any position)                   |
//|    mn - MagicNumber                (-1   - any magic number)               |
//+----------------------------------------------------------------------------+
int ExistPositions(string sy,int op=-1,int mn=-1)
{
   int pos=0;
   uint total=PositionsTotal();
//---
   for(uint i=0; i<total; i++)
   {
      if(SelectByIndex(i))
         if(PositionGetString(POSITION_SYMBOL)==sy)
            if(op<0 || PositionGetInteger(POSITION_TYPE)==op)
               if(mn<0 || PositionGetInteger(POSITION_MAGIC)==mn)
                  pos++;
   }
   return(pos);
}
//+------------------------------------------------------------------+
//| Select a position on the index                                   |
//+------------------------------------------------------------------+
bool SelectByIndex(const int index)
{
   ENUM_ACCOUNT_MARGIN_MODE margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE);
//---
   if(margin_mode==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
   {
      ulong ticket=PositionGetTicket(index);
      if(ticket==0)
         return(false);
   }
   else
   {
      string name=PositionGetSymbol(index);
      if(name=="")
         return(false);
   }
//---
   return(true);
}
//+------------------------------------------------------------------+
//| Trading Environment Initialization                               |
//+------------------------------------------------------------------+
void OnInitTrading()
{
   string array_used_symbols[];
//--- Fill in the array of used symbols
   CreateUsedSymbolsArray(SYMBOLS_MODE_CURRENT,"",array_used_symbols);
//--- Set the type of the used symbol list in the symbol collection and fill in the list of symbol timeseries
   trade.SetUsedSymbols(array_used_symbols);
//--- Pass all existing collections to the trading class
   trade.TradingOnInit();
   trade.TradingSetMagic(InpMagic);
   trade.TradingSetLogLevel(LOG_LEVEL_ERROR_MSG);
//--- Set synchronous passing of orders for all used symbols
   trade.TradingSetAsyncMode(false);
//--- Set correct order expiration and filling types to all trading objects
   trade.TradingSetCorrectTypeExpiration();
   trade.TradingSetCorrectTypeFilling();
}
//+------------------------------------------------------------------+

音声アラートの使用法の観点から、このコードをより詳細に検討してみましょう。自動売買ロボット初期化関数には、取引システムがターミナルでの取引を許可されているかどうかの確認が含まれています。このオプションを無効にすると、適切な音声アラートが再生され、ユーザに通知されます。次に、OnTick()関数で、目的の取引シグナルが見つかった場合、EAは目的の買いまたは売りシグナルが見つかったことを通知します。シグナルに従ってポジションを開こうとします。成功すると、別の音声アラートが再生され、ポジションが開かれたことをユーザに通知します。

ユーザがターミナルの[エキスパート]タブのテキストアラートを見逃す可能性があるため、これらの通知ははるかに効率的です。標準の音声アラートに関しては、指標とエキスパートアドバイザーで異なる場合があり、音声の意味が常に明確であるとは限りません。音声通知は正確な情報を提供するため、はるかに便利です。


クイック取引ツールでの実用的な適用

以前の記事では、手動トレーダー向けのツールキットを開発しました。このツールキットは、独立して市場へのエントリを検索し、手動で注文し、ポジションを管理して決済します。デモ目的で、このツールキットに音声通知のシステムを追加したいと思います。これは、音声アラート機能を任意のツールに簡単に追加できることも示しています。基礎として、この記事の添付ファイルを使用します。まず、音声アラートを追加するアクションとイベントのリストを定義しましょう。

  • 買いポジションまたは売りポジションを開くのに成功した
  • 未決注文の出すのと削除するのに成功した
  • エキスパートアドバイザーを使用して注文できるかどうかの確認

音声通知の統合を開始する前に、関連するライブラリをこのプロジェクトに関連付けます。Program.mqhを開いて次を冒頭に追加します。

//+------------------------------------------------------------------+
//|                                                      Program.mqh |
//|                                                         Alex2356 |
//|                    https://www.mql5.com/en/users/alex2356/       |
//+------------------------------------------------------------------+
#include <EasyAndFastGUI\WndEvents.mqh>
#include <DoEasy25\Engine.mqh>
#include "Defines.mqh"
#include <SoundsLib/SoundsLib.mqh>

CFastTradingクラスのprivateセクションに移動し、CSoundsLibクラスインスタンス変数を作成します。

   //---
   CSoundsLib        m_notify;

また、ツールキットに2つの新しいパラメータを設定します。これにより、通知の有効化/無効化と言語の選択が可能になります。SimpleTrading.mq5を開いて、EAのInput Parametersセクションに新しいパラメータを追加します

//+------------------------------------------------------------------+
//| Expert Advisor input parameters                                  |
//+------------------------------------------------------------------+
input int                  Inp_BaseFont      =  10;                  // Base FontSize
input color                Caption           =  C'0,130,225';        // Caption Color
input color                Background        =  clrWhite;            // Back color
input LANG                 Language          =  ENGLISH;             // Interface language
input ulong                MagicNumber       =  1111;                // Magic Number
//---
input bool                 UseVoiceNotify    =  true;                // Use Voice Notify
input LANGUAGE             NotifyLanguage    =  ENGLISH;             // Notification Language

CSoundsLibクラスインスタンスm_notifyに渡すには、CFastTrading基本クラスのpublicセクションに2つのメソッドを作成して実装します。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::SetNotifyLanguage(LANGUAGE lang)
{
   m_notify.Language(lang);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::UseVoiceNotify(bool state)
{
   m_notify.IsActive(state);
}
//+------------------------------------------------------------------+

SimpleTrading.mq5OnInit()関数に実装し、入力パラメータを新しく作成したメソッドに渡します。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
//---
   tick_counter=GetTickCount();
//--- Initialize class variables
   program.FontName("Trebuchet MS");
   program.FontSize(Inp_BaseFont);
   program.BackgroundColor(Background);
   program.CaptionColor(Caption);
   program.SetLanguage(Language);
   program.SetMagicNumber(MagicNumber);
   program.UseVoiceNotify(UseVoiceNotify);
   program.SetNotifyLanguage(NotifyLanguage);
//--- Set up the trading panel
   if(!program.CreateGUI())
   {
      Print(__FUNCTION__," > Failed to create graphical interface!");
      return(INIT_FAILED);
   }
   program.OnInitEvent();
//---
   return(INIT_SUCCEEDED);
}

このようにして、音声通知システムの主な入力パラメータを設定しました。ここで、売買市場のポジションを設定するメソッドを見つけます。これらは、CFastTrading基本クラスSetBuyOrder()およびSetSellOrder()メソッドです。 買い注文を出すメソッドの本体を開き、ポジションが正常に開かれたかどうかの確認が実行される部分を見つけます。そこに適切な音声アラートBUY_ORDER_SETを追加します

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::SetBuyOrder(int id,long lparam)
{
   if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_buy_execute.Id()) ||
         (id==CHARTEVENT_KEYDOWN && lparam==KEY_B))
   {
      //---
      double lot;
      if(m_switch_button[0].IsPressed())
         lot=LotPercent(Symbol(),ORDER_TYPE_BUY,SymbolInfoDouble(Symbol(),SYMBOL_ASK),StringToDouble(m_lot_edit[0].GetValue()));
      else
         lot=NormalizeLot(Symbol(),StringToDouble(m_lot_edit[0].GetValue()));
      if(m_switch_button[1].IsPressed() && m_switch_button[2].IsPressed())
      {
         double tp=double(m_tp_edit[0].GetValue());
         double sl=double(m_sl_edit[0].GetValue());
         if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp))
         {
            m_notify.Message(BUY_ORDER_SET);
            return(true);
         }
      }
      else if(!m_switch_button[1].IsPressed() && !m_switch_button[2].IsPressed())
      {
         int tp=int(m_tp_edit[0].GetValue());
         int sl=int(m_sl_edit[0].GetValue());
         if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp))
         {
            m_notify.Message(BUY_ORDER_SET);
            return(true);
         }
      }
      else if(m_switch_button[1].IsPressed() && !m_switch_button[2].IsPressed())
      {
         double tp=double(m_tp_edit[0].GetValue());
         int sl=int(m_sl_edit[0].GetValue());
         if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp))
         {
            m_notify.Message(BUY_ORDER_SET);
            return(true);
         }
      }
      else if(!m_switch_button[1].IsPressed() && m_switch_button[2].IsPressed())
      {
         int tp=int(m_tp_edit[0].GetValue());
         double sl=double(m_sl_edit[0].GetValue());
         if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp))
         {
            m_notify.Message(BUY_ORDER_SET);
            return(true);
         }
      }
   }
   return(false);
}

売りポジションを開くメソッドについても同じ変更を加えます。使用する音声アラートはSELL_ORDER_SETです。

bool CFastTrading::SetSellOrder(int id,long lparam)
{
   if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_sell_execute.Id()) ||
         (id==CHARTEVENT_KEYDOWN && lparam==KEY_S))
   {
      //---
      double lot;
      if(m_switch_button[3].IsPressed())
         lot=LotPercent(Symbol(),ORDER_TYPE_SELL,SymbolInfoDouble(Symbol(),SYMBOL_BID),StringToDouble(m_lot_edit[1].GetValue()));
      else
         lot=NormalizeLot(Symbol(),StringToDouble(m_lot_edit[1].GetValue()));
      //---
      if(m_switch_button[4].IsPressed() && m_switch_button[5].IsPressed())
      {
         double tp=double(m_tp_edit[1].GetValue());
         double sl=double(m_sl_edit[1].GetValue());
         if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp))
         {
            m_notify.Message(SELL_ORDER_SET);
            return(true);
         }
      }
      else if(!m_switch_button[4].IsPressed() && !m_switch_button[5].IsPressed())
      {
         int tp=int(m_tp_edit[1].GetValue());
         int sl=int(m_sl_edit[1].GetValue());
         if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp))
         {
            m_notify.Message(SELL_ORDER_SET);
            return(true);
         }
      }
      else if(!m_switch_button[4].IsPressed() && m_switch_button[5].IsPressed())
      {
         int tp=int(m_tp_edit[1].GetValue());
         double sl=double(m_sl_edit[1].GetValue());
         if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp))
         {
            m_notify.Message(SELL_ORDER_SET);
            return(true);
         }
      }
      else if(m_switch_button[4].IsPressed() && !m_switch_button[5].IsPressed())
      {
         double tp=double(m_tp_edit[1].GetValue());
         int sl=int(m_sl_edit[1].GetValue());
         if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp))
         {
            m_notify.Message(SELL_ORDER_SET);
            return(true);
         }
      }
   }
   return(false);
}

未決注文に移ります。ツールキットは4つのタイプをサポートし、それぞれに個別のメソッドがあります。

   bool              SetBuyStopOrder(int id,long lparam);
   bool              SetSellStopOrder(int id,long lparam);
   bool              SetBuyLimitOrder(int id,long lparam);
   bool              SetSellLimitOrder(int id,long lparam);

それぞれに個別の音声通知を設定する必要があります。これはBuyStop注文の例ですが、他の注文も同様の方法で設定されます。以下のコードからわかるように、BUYSTOP_ORDER_SET通知が使用されます。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::SetBuyStopOrder(int id,long lparam)
{
   if(!m_orders_windows[1].IsVisible())
      return(false);
   if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_buystop_execute.Id()) ||
         (id==CHARTEVENT_KEYDOWN && lparam==KEY_1))
   {
      //---
      double lot;
      if(m_p_switch_button[0].IsPressed())
         lot=LotPercent(Symbol(),ORDER_TYPE_BUY,SymbolInfoDouble(Symbol(),SYMBOL_ASK),StringToDouble(m_lot_edit[2].GetValue()));
      else
         lot=NormalizeLot(Symbol(),StringToDouble(m_lot_edit[2].GetValue()));
      //---
      double pr=double(m_pr_edit[0].GetValue());
      //---
      if(m_p_switch_button[1].IsPressed() && m_p_switch_button[2].IsPressed())
      {
         double tp=double(m_tp_edit[2].GetValue());
         double sl=double(m_sl_edit[2].GetValue());
         if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number))
         {
            m_notify.Message(BUYSTOP_ORDER_SET);
            return(true);
         }
      }
      else if(!m_p_switch_button[1].IsPressed() && !m_p_switch_button[2].IsPressed())
      {
         int tp=int(m_tp_edit[2].GetValue());
         int sl=int(m_sl_edit[2].GetValue());
         if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number))
         {
            m_notify.Message(BUYSTOP_ORDER_SET);
            return(true);
         }
      }
      else if(m_p_switch_button[1].IsPressed() && !m_p_switch_button[2].IsPressed())
      {
         double tp=double(m_tp_edit[2].GetValue());
         int sl=int(m_sl_edit[2].GetValue());
         if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number))
         {
            m_notify.Message(BUYSTOP_ORDER_SET);
            return(true);
         }
      }
      else if(!m_p_switch_button[1].IsPressed() && m_p_switch_button[2].IsPressed())
      {
         int tp=int(m_tp_edit[2].GetValue());
         double sl=double(m_sl_edit[2].GetValue());
         if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number))
         {
            m_notify.Message(BUYSTOP_ORDER_SET);
            return(true);
         }
      }
   }
   return(false);
}

これで、未決注文の通知の準備ができたら、以前に行った注文の削除の通知を追加する必要があります。RemoveOrder()メソッドは、テーブル内の未決注文のどれを選択するかを決定します。選択した注文は、変更または削除できます。ここでは、[削除]ボタンをクリックして注文を削除します。 

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::RemoveOrder(long lparam)
{
//--- Check the element ID
   if(lparam==m_small_button[3].Id())
   {
      //--- Get index and symbol
      if(m_table_orders.SelectedItem()==WRONG_VALUE)
         return(false);
      int row=m_table_orders.SelectedItem();
      ulong ticket=(ulong)m_table_orders.GetValue(0,row);
      //---
      if(OrderSelect(ticket))
      {
         string position_symbol=OrderGetString(ORDER_SYMBOL);                          // symbol
         ulong  magic=OrderGetInteger(ORDER_MAGIC);                                    // order MagicNumber
         ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE);            // order type
         if(type==ORDER_TYPE_BUY_STOP)
            m_notify.Message(BUYSTOP_ORDER_DELETE);
         else if(type==ORDER_TYPE_SELL_STOP)
            m_notify.Message(SELLSTOP_ORDER_DELETE);
         else if(type==ORDER_TYPE_BUY_LIMIT)
            m_notify.Message(BUYLIMIT_ORDER_DELETE);
         else if(type==ORDER_TYPE_SELL_LIMIT)
            m_notify.Message(SELLLIMIT_ORDER_DELETE);
         //--- declare the request and the result
         MqlTradeRequest request;
         MqlTradeResult  result;
         //--- zeroing the request and result values
         ZeroMemory(request);
         ZeroMemory(result);
         //--- set the operation parameters
         request.action=TRADE_ACTION_REMOVE;             // trading operation type
         request.order = ticket;                         // order ticket
         //--- sending a request
         bool res=true;
         for(int j=0; j<5; j++)
         {
            res=OrderSend(request,result);
            if(res && result.retcode==TRADE_RETCODE_DONE)
               return(true);
            else
               PrintFormat("OrderSend error %d",GetLastError());  // if unable to send the request, output the error code
         }
      }
   }
//---
   return(false);
}

メソッド本体の変更について詳しく考えてみましょう。選択した注文のチケットが決定されると、MqlTradeRequest構造に入力し、OrderSend()メソッドを呼び出すことにより、注文の削除をリクエストするために必要なデータを受け取ります。テーブルで選択された未決注文のタイプは、type変数に基づいて決定されます。変数値に基づいて、Message()メソッドで適切な音声通知を設定します。

実装する最後のタスクは、MetaTrader5ターミナルで自動取引が無効になっている場合に音声通知を追加することです。ツールキットは実際にはエキスパートアドバイザーです。ユーザは手動で注文しますが、ターミナルとブローカーはそれらを自動取引として認識します。自動取引かどうかの確認を追加するには、基本クラスに移動し、OnEvent()ハンドラ->ON_END_CREATE_GUIセクションを見つけ、適切な音声通知で確認を追加します

// --- GUI creation completion
   if(id==CHARTEVENT_CUSTOM+ON_END_CREATE_GUI)
   {
      //---
      SetButtonParam(m_switch_button[0],LOT);
      SetButtonParam(m_switch_button[1],POINTS);
      SetButtonParam(m_switch_button[2],POINTS);
      SetButtonParam(m_switch_button[3],LOT);
      SetButtonParam(m_switch_button[4],POINTS);
      SetButtonParam(m_switch_button[5],POINTS);
      //---
      SetButtonParam(m_p_switch_button[0],LOT);
      SetButtonParam(m_p_switch_button[1],POINTS);
      SetButtonParam(m_p_switch_button[2],POINTS);
      SetButtonParam(m_p_switch_button[3],LOT);
      SetButtonParam(m_p_switch_button[4],POINTS);
      SetButtonParam(m_p_switch_button[5],POINTS);
      SetButtonParam(m_p_switch_button[6],LOT);
      SetButtonParam(m_p_switch_button[7],POINTS);
      SetButtonParam(m_p_switch_button[8],POINTS);
      SetButtonParam(m_p_switch_button[9],LOT);
      SetButtonParam(m_p_switch_button[10],POINTS);
      SetButtonParam(m_p_switch_button[11],POINTS);
      //---
      if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
         m_notify.Message(AUTO_TRADING_OFF);
   }

以下のビデオは、クイック取引ツールキットで音声通知がどのように機能するかを示しています。このツールキットでは、アラートが市場ポジションと未決注文に使用されます。


終わりに

添付されたアーカイブには、リストされたすべてのファイルが含まれています。これらのファイルは、適切なフォルダにあります。正しく動作させるためには、MQL5フォルダをターミナルフォルダに保存するだけです。MQL5フォルダのあるルートディレクトリを開くには、MetaTrader 5ターミナルでCtrl+Shift+Dキーの組み合わせを押すか、下記の図7にあるようにコンテキストメニューを使用します。


図7 MetaTrader 5ターミナルルートでMQL5フォルダを開く


MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/8111

添付されたファイル |
MQL5.zip (8868.77 KB)
DoEasyライブラリの時系列(第47部): 複数銘柄・複数期間標準指標 DoEasyライブラリの時系列(第47部): 複数銘柄・複数期間標準指標
この記事では、標準指標を操作する方法の開発を開始します。これにより、最終的には、ライブラリクラスに基づいて複数銘柄の複数期間の標準指標を作成できるようになります。さらに、「スキップされたバー」イベントを時系列クラスに追加し、ライブラリ準備関数をCEngineクラスに移動することで、メインプログラムコードからの過度の負荷を排除します。
買われすぎ・売られすぎゾーンの検出方法について。 第一部 買われすぎ・売られすぎゾーンの検出方法について。 第一部
買われすぎ/売られすぎのゾーンは、相場の特定の状態を特徴づけ、有価証券の価格の弱い変化によって区別されます。 シナミクスにおけるこの不利な変化は、あらゆるスケールのトレンドの成長の最終段階で顕著です。 トレードにおける利益価値は、可能な限り大きなトレンド振幅をカバーできるかどうかに直接依存するため、このようなゾーンを検出する精度は、どのような証券でも重要な課題となります。
外部アプリケーションで暗号を使用する 外部アプリケーションで暗号を使用する
この記事では、MetaTraderや外部アプリケーションでのオブジェクトの暗号化/復号化について考えてみます。 今回の目的は、同じ初期データで同じ結果が得られる条件を決めることです。
確率論と数理統計学と例(第1部): 基礎理論と初等理論 確率論と数理統計学と例(第1部): 基礎理論と初等理論
取引とは、常に不確実性に直面して意思決定を行うことです。つまり、これらの決定が行われた時点では、決定の結果が明確ではありません。これには、そのようなケースを意味ある方法で説明できるようにする数学的モデルの構築への理論的アプローチの重要性が必然的に伴います。