DoEasyライブラリでのその他のクラス(第66部): MQL5.comシグナルコレクションクラス
内容
概念
前回の記事では、シグナルオブジェクトクラスを作成しました。これは、MQL5.comシグナルサービスでブロードキャストされる複数のシグナルのうちの1つです。
今日はシグナルデータベースで利用可能なシグナルのコレクションクラスを作成します。これは、SignalBaseSelect()関数を使用して必要なシグナルのインデックスを指定することによって取得できます。
このコレクションを使用すると、データベースに存在するすべてのシグナルを、検索と並べ替えに便利なリストとして保存できます。シグナルのリストをさまざまなプロパティによって検出して返すことができます。たとえば、無料または有料のシグナルのみのリストを取得してパラメータの1つ(シグナルの収益性など)で並べ替えたり、指定された値と等しい(/超える/より小さい)パラメータによってリスト内のシグナルインデックスをすぐに取得したりできます。必要なシグナルがわかっていれば、コレクション内ですばやく見つけることができます。
コレクションクラスで、コレクションで選択されたシグナルをサブスクライブする機能または現在の口座のシグナルからサブスクライブを解除する機能を実装します。
MQL5.comシグナルサービスオブジェクトの使用とは別に、DOMスナップショットオブジェクトの作成時に売買注文量をすぐに計算できるようにプロパティを追加することで、板情報(DOM)スナップショットオブジェクトクラスを改善します。 これにより、エンドユーザーはDOMを操作するときに追加の計算を行う必要がなくなります。 各DOMスナップショットの売買量の合計がすぐにわかります。DOMとそのボリュームを使用してストラテジーを作成するときに、DOMで買い注文と売り注文を追加で検索し、その後ボリュームを合計する必要はありません。
ライブラリクラスの改善
いつものように、すべての新しいライブラリメッセージをすぐに\MQL5\Include\DoEasy\Data.mqhに追加しましょう。
まず新しいメッセージインデックスを追加します。
//--- CMarketBookSnapshot MSG_MBOOK_SNAP_TEXT_SNAPSHOT, // DOM snapshot MSG_MBOOK_SNAP_VOLUME_BUY, // Buy volume MSG_MBOOK_SNAP_VOLUME_SELL, // Sell volume //--- CMBookSeries MSG_MBOOK_SERIES_TEXT_MBOOKSERIES, // DOM snapshot series MSG_MBOOK_SERIES_ERR_ADD_TO_LIST, // Error. Failed to add DOM snapshot series to the list
...
//--- CMQLSignal MSG_SIGNAL_MQL5_TEXT_SIGNAL, // Signal MSG_SIGNAL_MQL5_TEXT_SIGNAL_MQL5, // MQL5.com Signals service signal MSG_SIGNAL_MQL5_TRADE_MODE, // Account type MSG_SIGNAL_MQL5_DATE_PUBLISHED, // Publication date MSG_SIGNAL_MQL5_DATE_STARTED, // Monitoring start date MSG_SIGNAL_MQL5_DATE_UPDATED, // Date of the latest update of the trading statistics MSG_SIGNAL_MQL5_ID, // ID MSG_SIGNAL_MQL5_LEVERAGE, // Trading account leverage MSG_SIGNAL_MQL5_PIPS, // Trading result in pips MSG_SIGNAL_MQL5_RATING, // Position in the signal rating MSG_SIGNAL_MQL5_SUBSCRIBERS, // Number of subscribers MSG_SIGNAL_MQL5_TRADES, // Number of trades MSG_SIGNAL_MQL5_SUBSCRIPTION_STATUS, // Status of account subscription to a signal MSG_SIGNAL_MQL5_EQUITY, // Account equity MSG_SIGNAL_MQL5_GAIN, // Account growth in % MSG_SIGNAL_MQL5_MAX_DRAWDOWN, // Maximum drawdown MSG_SIGNAL_MQL5_PRICE, // Signal subscription price MSG_SIGNAL_MQL5_ROI, // Signal ROI (Return on Investment) in % MSG_SIGNAL_MQL5_AUTHOR_LOGIN, // Author login MSG_SIGNAL_MQL5_BROKER, // Broker (company) name MSG_SIGNAL_MQL5_BROKER_SERVER, // Broker server MSG_SIGNAL_MQL5_NAME, // Name MSG_SIGNAL_MQL5_CURRENCY, // Account currency MSG_SIGNAL_MQL5_TEXT_GAIN, // Growth MSG_SIGNAL_MQL5_TEXT_DRAWDOWN, // Drawdown MSG_SIGNAL_MQL5_TEXT_SUBSCRIBERS, // Subscribers //--- CMQLSignalsCollection MSG_MQLSIG_COLLECTION_TEXT_MQL5_SIGNAL_COLLECTION, // Collection of MQL5.com Signals service signals MSG_MQLSIG_COLLECTION_TEXT_SIGNALS_PAID, // Paid signals MSG_MQLSIG_COLLECTION_TEXT_SIGNALS_FREE, // Free signals MSG_MQLSIG_COLLECTION_TEXT_SIGNALS_NEW, // New signal added to collection MSG_MQLSIG_COLLECTION_ERR_FAILED_GET_SIGNAL, // Failed to receive signal from collection MSG_SIGNAL_INFO_PARAMETERS, // Signal copying parameters MSG_SIGNAL_INFO_EQUITY_LIMIT, // Percentage for converting deal volume MSG_SIGNAL_INFO_SLIPPAGE, // Market order slippage when synchronizing positions and copying deals MSG_SIGNAL_INFO_VOLUME_PERCENT, // Limitation on signal equity MSG_SIGNAL_INFO_CONFIRMATIONS_DISABLED, // Enable synchronization without confirmation dialog MSG_SIGNAL_INFO_COPY_SLTP, // Copy Stop Loss and Take Profit MSG_SIGNAL_INFO_DEPOSIT_PERCENT, // Limit by deposit MSG_SIGNAL_INFO_ID, // Signal ID MSG_SIGNAL_INFO_SUBSCRIPTION_ENABLED, // Enable copying deals by subscription MSG_SIGNAL_INFO_TERMS_AGREE, // Agree to the terms of use of the Signals service MSG_SIGNAL_INFO_NAME, // Signal name MSG_SIGNAL_INFO_SIGNALS_PERMISSION, // Allow using signals for program MSG_SIGNAL_INFO_TEXT_SIGNAL_SUBSCRIBED, // Subscribed to signal MSG_SIGNAL_INFO_TEXT_SIGNAL_UNSUBSCRIBED, // Unsubscribed from signal MSG_SIGNAL_INFO_ERR_SIGNAL_NOT_ALLOWED, // Signal service disabled for program MSG_SIGNAL_INFO_TEXT_CHECK_SETTINGS, // Please check program settings (Common-->Allow modification of Signals settings) }; //+------------------------------------------------------------------+
次に、新しく追加されたインデックスに対応するテキストメッセージを追加します。
//--- CMarketBookSnapshot {"Снимок стакана цен","Depth of Market Snapshot"}, {"Объём на покупку","Buy Volume"}, {"Объём на продажу","Sell Volume"}, //--- CMBookSeries {"Серия снимков стакана цен","Series of shots of the Depth of Market"}, {"Ошибка. Не удалось добавить серию снимков стакана цен в список","Error. Failed to add a shots series of the Depth of Market to the list"}, //--- CMBookSeriesCollection {"Коллекция серий снимков стакана цен","Collection of series of the Depth of Market shot"}, //--- CMQLSignal {"Сигнал","Signal"}, {"Сигнал сервиса сигналов mql5.com","Signal from mql5.com signal service"}, {"Тип счета","Account type"}, {"Дата публикации","Publication date"}, {"Дата начала мониторинга","Monitoring starting date"}, {"Дата последнего обновления торговой статистики","The date of the last update of the signal's trading statistics"}, {"ID","ID"}, {"Плечо торгового счета","Account leverage"}, {"Результат торговли в пипсах","Profit in pips"}, {"Позиция в рейтинге сигналов","Position in rating"}, {"Количество подписчиков","Number of subscribers"}, {"Количество трейдов","Number of trades"}, {"Состояние подписки счёта на этот сигнал","Account subscription status for this signal"}, {"Средства на счете","Account equity"}, {"Прирост счета в процентах","Account gain"}, {"Максимальная просадка","Account maximum drawdown"}, {"Цена подписки на сигнал","Signal subscription price"}, {"Значение ROI (Return on Investment) сигнала в %","Return on Investment (%)"}, {"Логин автора","Author login"}, {"Наименование брокера (компании)","Broker name (company)"}, {"Сервер брокера","Broker server"}, {"Имя","Name"}, {"Валюта счета","Base currency"}, {"Прирост","Gain"}, {"Просадка","Drawdown"}, {"Подписчиков","Subscribers"}, //--- CMQLSignalsCollection {"Коллекция сигналов сервиса сигналов mql5.com","Collection of signals from the mql5.com signal service"}, {"Платных сигналов","Paid signals"}, {"Бесплатных сигналов","Free signals"}, {"Новый сигнал добавлен в коллекцию","New signal added to collection"}, {"Не удалось получить сигнал из коллекции","Failed to get signal from collection"}, {"Параметры копирования сигнала","Signal copying parameters"}, {"Процент для конвертации объема сделки","Equity limit"}, {"Проскальзывание, с которым выставляются рыночные ордера при синхронизации позиций и копировании сделок","Slippage (used when placing market orders in synchronization of positions and copying of trades)"}, {"Ограничение по средствам для сигнала","Maximum percent of deposit used"}, {"Разрешение синхронизации без показа диалога подтверждения","Allow synchronization without confirmation dialog"}, {"Копирование Stop Loss и Take Profit","Copy Stop Loss and Take Profit"}, {"Ограничение по депозиту","Deposit percent"}, {"Идентификатор сигнала","Signal ID"}, {"Разрешение на копирование сделок по подписке","Permission to copy trades by subscription"}, {"Согласие с условиями использования сервиса \"Сигналы\"","Agree to the terms of use of the \"Signals\" service"}, {"Имя сигнала","Signal name"}, {"Разрешение на работу с сигналами для программы","Permission to work with signals for the program"}, {"Осуществлена подписка на сигнал","Signal subscribed"}, {"Осуществлена отписка от сигнала","Signal unsubscribed"}, {"Работа с сервисом сигналов для программы не разрешена","Work with the \"Signals\" service is not allowed for the program"}, { "Пожалуйста, проверьте настройки программы (Общие --> Разрешить изменение настроек Сигналов)", "Please check the program settings (Common --> Allow modification of Signals settings)" }, }; //+---------------------------------------------------------------------+
操作ログにメッセージを表示する場合(特にデバッグメッセージ)、メッセージ自体の先頭にメッセージの送信元のメソッドの名前を示すことがよくあります。第19部ではライブラリメッセージのクラスを開発しましたが、現在は、標準のPrint()関数を介して操作ログに表示する必要があるメッセージのインデックスを指定するためにのみ使用しています。間もなくグラフィックを使用するための新しいライブラリセクションを開始する予定なので、ライブラリメッセージを表示するためには徐々にこのクラスを使用するようになります。今日は、ToLog()メソッドのオーバーロードを追加して、クラスのメソッドまたはメソッドが呼び出されたプログラムの関数にメッセージ「ソース」を追加で渡すことができるようにします。ToLog()メソッドの2つのバリアントがあり、ソース関数またはメソッドを指定した場合と指定しない場合でメッセージを表示できます。
\MQL5\Include\DoEasy\Services\Message.mqhを開いて、オーバーロードされたメソッドの宣言を追加します。
//--- (1,2) display a message in the journal by ID, (3) to e-mail, (4) to a mobile device static void ToLog(const int msg_id,const bool code=false); static void ToLog(const string source,const int msg_id,const bool code=false); static bool ToMail(const string message,const string subject=NULL); static bool Push(const string message); //--- (1) send a file to FTP, (2) return an error code static bool ToFTP(const string filename,const string ftp_path=NULL); static int GetError(void) { return CMessage::m_global_error; }
クラス本体の外側で実装しましょう。
//+------------------------------------------------------------------+ //| Display a message in the journal by a message ID | //+------------------------------------------------------------------+ void CMessage::ToLog(const int msg_id,const bool code=false) { CMessage::GetTextByID(msg_id); ::Print(m_text,(!code || msg_id>ERR_USER_ERROR_FIRST-1 ? "" : " "+CMessage::Retcode(msg_id))); } //+------------------------------------------------------------------+ //| Display a message in the journal by a message ID | //+------------------------------------------------------------------+ void CMessage::ToLog(const string source,const int msg_id,const bool code=false) { CMessage::GetTextByID(msg_id); ::Print(source,m_text,(!code || msg_id>ERR_USER_ERROR_FIRST-1 ? "" : " "+CMessage::Retcode(msg_id))); } //+------------------------------------------------------------------+
メソッドを呼び出す最初の形式とは異なり、その2番目の形式はさらに別の入力を備えています。この入力では、ToLog()メソッドを呼び出す必要のあるメソッドまたは関数の名前が渡され、メッセージの前に操作ログに表示されます。
このクラスには、後続の記事ですべてのライブラリクラスのメッセージをこのクラスを使用して表示するようにするときに、改善するために戻ります。
\MQL5\Include\DoEasy\Objects\Book\MarketBookSnapshot.mqhのCMBookSnapshotクラスを改善しましょう。
クラスのprivateセクションで、 DOMスナップショットの売買ボリュームの合計を格納するためのクラスメンバー変数を追加します。
//+------------------------------------------------------------------+ //| "DOM snapshot" class | //+------------------------------------------------------------------+ class CMBookSnapshot : public CBaseObj { private: string m_symbol; // Symbol long m_time; // Snapshot time int m_digits; // Symbol's Digits long m_volume_buy; // DOM buy volume long m_volume_sell; // DOM sell volume double m_volume_buy_real; // DOM buy volume with an increased accuracy double m_volume_sell_real; // DOM sell volume with an increased accuracy CArrayObj m_list; // List of DOM order objects public:
クラスセクションのDOMスナップショットオブジェクトプロパティへのアクセスを簡略化するメソッドのセクションで、これらの新しく追加されたクラスプロパティを返すメソッドと説明を表示するメソッドを追加します。
//+----------------------------------------------------------------------+ //|Methods of a simplified access to the DOM snapshot object properties | //+----------------------------------------------------------------------+ //--- Set (1) a symbol, (2) a DOM snapshot time and (3) the specified time for all DOM orders void SetSymbol(const string symbol) { this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol); } void SetTime(const long time_msc) { this.m_time=time_msc; } void SetTimeToOrders(const long time_msc); //--- Return (1) a DOM symbol, (2) symbol's Digits and (3) a snapshot time //--- (4) buy and (5) sell DOM snapshot volume //--- with increased accuracy for (6) buying and (7) selling, string Symbol(void) const { return this.m_symbol; } int Digits(void) const { return this.m_digits; } long Time(void) const { return this.m_time; } long VolumeBuy(void) const { return this.m_volume_buy; } long VolumeSell(void) const { return this.m_volume_sell; } double VolumeBuyReal(void) const { return this.m_volume_buy_real; } double VolumeSellReal(void) const { return this.m_volume_sell_real; } //--- Return the description of DOM (1) buy and (2) sell volume string VolumeBuyDescription(void); string VolumeSellDescription(void); }; //+------------------------------------------------------------------+
新しいDOMスナップショットオブジェクトを作成すると、そのすべての注文がループで表示され、これらの注文のオブジェクトが作成されてリストに送信されます。次に、クラスコンストラクタで注文タイプを検討し、現在の注文タイプに応じて、買い注文と売り注文の合計ボリュームを格納する変数に現在の注文ボリュームをすぐに追加する必要があります。したがって、各変数は、DOMスナップショットオブジェクトを作成するとすぐに、最終的に買い注文または売り注文の合計ボリュームを格納します。
これらの改善をクラスパラメトリックコンストラクタに追加しましょう。
//+------------------------------------------------------------------+ //| Parametric constructor | //+------------------------------------------------------------------+ CMBookSnapshot::CMBookSnapshot(const string symbol,const long time,MqlBookInfo &book_array[]) : m_time(time) { //--- Set a symbol this.SetSymbol(symbol); //--- Clear the list this.m_list.Clear(); //--- In the loop by the structure array int total=::ArraySize(book_array); this.m_volume_buy=this.m_volume_sell=0; this.m_volume_buy_real=this.m_volume_sell_real=0; for(int i=0;i<total;i++) { //--- Create order objects of the current DOM snapshot depending on the order type CMarketBookOrd *mbook_ord=NULL; switch(book_array[i].type) { case BOOK_TYPE_BUY : mbook_ord=new CMarketBookBuy(this.m_symbol,book_array[i]); break; case BOOK_TYPE_SELL : mbook_ord=new CMarketBookSell(this.m_symbol,book_array[i]); break; case BOOK_TYPE_BUY_MARKET : mbook_ord=new CMarketBookBuyMarket(this.m_symbol,book_array[i]); break; case BOOK_TYPE_SELL_MARKET : mbook_ord=new CMarketBookSellMarket(this.m_symbol,book_array[i]); break; default: break; } if(mbook_ord==NULL) continue; //--- Set the DOM snapshot time for the order mbook_ord.SetTime(this.m_time); //--- Set the sorted list flag for the list (by the price value) and add the current order object to it //--- If failed to add the object to the DOM order list, remove the order object this.m_list.Sort(SORT_BY_MBOOK_ORD_PRICE); if(!this.m_list.InsertSort(mbook_ord)) delete mbook_ord; //--- If the order object is successfully added to the DOM order list, supplement the total snapshot volumes else { switch(mbook_ord.TypeOrd()) { case BOOK_TYPE_BUY : this.m_volume_buy+=mbook_ord.Volume(); this.m_volume_buy_real+=mbook_ord.VolumeReal(); break; case BOOK_TYPE_SELL : this.m_volume_sell+=mbook_ord.Volume(); this.m_volume_sell_real+=mbook_ord.VolumeReal(); break; case BOOK_TYPE_BUY_MARKET : this.m_volume_buy+=mbook_ord.Volume(); this.m_volume_buy_real+=mbook_ord.VolumeReal(); break; case BOOK_TYPE_SELL_MARKET : this.m_volume_buy+=mbook_ord.Volume(); this.m_volume_buy_real+=mbook_ord.VolumeReal(); break; default: break; } } } } //+------------------------------------------------------------------+
まず、すべてのDOMスナップショットの売買注文の合計ボリュームを格納する変数を初期化します。次に、すべてのDOM注文によるループ本体で、注文タイプに応じて、現在の注文ボリュームを合計ボリュームを格納する適切な変数に追加します。したがって、すべてのDOMスナップショット注文によるループの完了時に、売買ボリュームの合計がすべての変数に格納されます。
操作ログ内のオブジェクトの簡単な説明とすべてのオブジェクトプロパティを表示するメソッドは、売買の合計量の表示を受け取ります。
//+------------------------------------------------------------------+ //| Display a short description of the object in the journal | //+------------------------------------------------------------------+ void CMBookSnapshot::PrintShort(void) { string vol_buy="Buy vol: "+(this.VolumeBuyReal()>0 ? ::DoubleToString(this.VolumeBuyReal(),2) : (string)this.VolumeBuy()); string vol_sell="Sell vol: "+(this.VolumeSellReal()>0 ? ::DoubleToString(this.VolumeSellReal(),2) : (string)this.VolumeSell()); ::Print(this.Header()," ",vol_buy,", ",vol_sell," ("+TimeMSCtoString(this.m_time),")"); } //+------------------------------------------------------------------+ //| Display object properties in the journal | //+------------------------------------------------------------------+ void CMBookSnapshot::Print(void) { string vol_buy=CMessage::Text(MSG_MBOOK_SNAP_VOLUME_BUY)+": "+(this.VolumeBuyReal()>0 ? ::DoubleToString(this.VolumeBuyReal(),2) : (string)this.VolumeBuy()); string vol_sell=CMessage::Text(MSG_MBOOK_SNAP_VOLUME_SELL)+": "+(this.VolumeSellReal()>0 ? ::DoubleToString(this.VolumeSellReal(),2) : (string)this.VolumeSell()); ::Print(this.Header(),": ",vol_buy,", ",vol_sell," ("+TimeMSCtoString(this.m_time),"):"); this.m_list.Sort(SORT_BY_MBOOK_ORD_PRICE); for(int i=this.m_list.Total()-1;i>WRONG_VALUE;i--) { CMarketBookOrd *ord=this.m_list.At(i); if(ord==NULL) continue; ::Print("- ",ord.Header()); } } //+------------------------------------------------------------------+
クラス本体の外で、2つの新しいDOMの売買ボリュームの説明を返すメソッドを実装します。
//+------------------------------------------------------------------+ //| Return the DOM buy volume description | //+------------------------------------------------------------------+ string CMBookSnapshot::VolumeBuyDescription(void) { return(CMessage::Text(MSG_MBOOK_SNAP_VOLUME_BUY)+": "+(this.VolumeBuyReal()>0 ? ::DoubleToString(this.VolumeBuyReal(),2) : (string)this.VolumeBuy())); } //+------------------------------------------------------------------+ //| Return the DOM sell volume description | //+------------------------------------------------------------------+ string CMBookSnapshot::VolumeSellDescription(void) { return(CMessage::Text(MSG_MBOOK_SNAP_VOLUME_SELL)+": "+(this.VolumeSellReal()>0 ? ::DoubleToString(this.VolumeSellReal(),2) : (string)this.VolumeSell())); } //+------------------------------------------------------------------+
どちらのメソッドでも、精度の向上が確認されます。ゼロを超える場合は、ヘッダー+ボリューム値(実数)が返されます。それ以外の場合は、整数が返されます。
\MQL5\Include\DoEasy\Collections\BookSeriesCollection.mqhのCMBookSeriesCollection DOMスナップショットシリーズコレクションクラス、つまりそのpublicセクションには、リストオブジェクトプロパティの指定された基準でリストを返すメソッドを作成します。
public: //--- Return (1) itself and (2) the DOM series collection list CMBookSeriesCollection *GetObject(void) { return &this; } CArrayObj *GetList(void) { return &this.m_list; } //--- Return the list by selected (1) integer, (2) real and (3) string properties meeting the compared criterion CArrayObj *GetList(ENUM_MBOOK_ORD_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByMBookProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_MBOOK_ORD_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByMBookProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_MBOOK_ORD_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByMBookProperty(this.GetList(),property,value,mode); } //--- Return the number of DOM series in the list int DataTotal(void) const { return this.m_list.Total(); } //--- Return the pointer to the DOM series object (1) by symbol and (2) by index in the list
\MQL5\Include\DoEasy\Objects\MQLSignalBase\MQLSignal.mqhのCMQLSignal DOM注文オブジェクトクラスで、オブジェクトの説明の前にハイフンを表示する必要があることを示すフラグ値をPrintShort()メソッドに追加します。
//--- Display the description of object properties in the journal (full_prop=true - all properties, false - supported ones only) void Print(const bool full_prop=false); //--- Display a short description of the object in the journal virtual void PrintShort(const bool dash=false); //--- Return the object short name virtual string Header(const bool shrt=false);
メソッド本体に変更を加えましょう。
//+------------------------------------------------------------------+ //| Display a short description of the object in the journal | //+------------------------------------------------------------------+ void CMQLSignal::PrintShort(const bool dash=false) { ::Print ( (dash ? "- " : ""),this.Header(true), " \"",this.Name(),"\". ", CMessage::Text(MSG_SIGNAL_MQL5_AUTHOR_LOGIN),": ",this.AuthorLogin(), ", ID ",this.ID(), ", ",CMessage::Text(MSG_SIGNAL_MQL5_TEXT_GAIN),": ",::DoubleToString(this.Gain(),2), ", ",CMessage::Text(MSG_SIGNAL_MQL5_TEXT_DRAWDOWN),": ",::DoubleToString(this.MaxDrawdown(),2), ", ",CMessage::Text(MSG_LIB_TEXT_REQUEST_PRICE),": ",::DoubleToString(this.Price(),2), ", ",CMessage::Text(MSG_SIGNAL_MQL5_TEXT_SUBSCRIBERS),": ",this.Subscribers() ); } //+------------------------------------------------------------------+
渡された値に応じて、オブジェクトの説明の前にハイフンが表示される場合と表示されない場合があります。サブスクライバーの数は、説明の最後に設定されています。
クラス本体の最後に、オブジェクトによって記述されたシグナルサブスクリプションを実行する新しいメソッドを追加します。
//--- Return the account type name string TradeModeDescription(void); //--- Subscribe to a signal bool Subscribe(void) { return ::SignalSubscribe(this.ID()); } }; //+------------------------------------------------------------------+
クラスコンストラクタで、シグナルサブスクリプションステータスを格納する変数の初期化を修正します。
//+------------------------------------------------------------------+ //| Parametric constructor | //+------------------------------------------------------------------+ CMQLSignal::CMQLSignal(const long signal_id) { this.m_long_prop[SIGNAL_MQL5_PROP_ID] = signal_id; this.m_long_prop[SIGNAL_MQL5_PROP_SUBSCRIPTION_STATUS] = (::SignalInfoGetInteger(SIGNAL_INFO_ID)==signal_id); this.m_long_prop[SIGNAL_MQL5_PROP_TRADE_MODE] = ::SignalBaseGetInteger(SIGNAL_BASE_TRADE_MODE); this.m_long_prop[SIGNAL_MQL5_PROP_DATE_PUBLISHED] = ::SignalBaseGetInteger(SIGNAL_BASE_DATE_PUBLISHED); this.m_long_prop[SIGNAL_MQL5_PROP_DATE_STARTED] = ::SignalBaseGetInteger(SIGNAL_BASE_DATE_STARTED); this.m_long_prop[SIGNAL_MQL5_PROP_DATE_UPDATED] = ::SignalBaseGetInteger(SIGNAL_BASE_DATE_UPDATED); this.m_long_prop[SIGNAL_MQL5_PROP_LEVERAGE] = ::SignalBaseGetInteger(SIGNAL_BASE_LEVERAGE); this.m_long_prop[SIGNAL_MQL5_PROP_PIPS] = ::SignalBaseGetInteger(SIGNAL_BASE_PIPS); this.m_long_prop[SIGNAL_MQL5_PROP_RATING] = ::SignalBaseGetInteger(SIGNAL_BASE_RATING); this.m_long_prop[SIGNAL_MQL5_PROP_SUBSCRIBERS] = ::SignalBaseGetInteger(SIGNAL_BASE_SUBSCRIBERS); this.m_long_prop[SIGNAL_MQL5_PROP_TRADES] = ::SignalBaseGetInteger(SIGNAL_BASE_TRADES); this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_BALANCE)] = ::SignalBaseGetDouble(SIGNAL_BASE_BALANCE); this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_EQUITY)] = ::SignalBaseGetDouble(SIGNAL_BASE_EQUITY); this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_GAIN)] = ::SignalBaseGetDouble(SIGNAL_BASE_GAIN); this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_MAX_DRAWDOWN)] = ::SignalBaseGetDouble(SIGNAL_BASE_MAX_DRAWDOWN); this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_PRICE)] = ::SignalBaseGetDouble(SIGNAL_BASE_PRICE); this.m_double_prop[this.IndexProp(SIGNAL_MQL5_PROP_ROI)] = ::SignalBaseGetDouble(SIGNAL_BASE_ROI); this.m_string_prop[this.IndexProp(SIGNAL_MQL5_PROP_AUTHOR_LOGIN)] = ::SignalBaseGetString(SIGNAL_BASE_AUTHOR_LOGIN); this.m_string_prop[this.IndexProp(SIGNAL_MQL5_PROP_BROKER)] = ::SignalBaseGetString(SIGNAL_BASE_BROKER); this.m_string_prop[this.IndexProp(SIGNAL_MQL5_PROP_BROKER_SERVER)]= ::SignalBaseGetString(SIGNAL_BASE_BROKER_SERVER); this.m_string_prop[this.IndexProp(SIGNAL_MQL5_PROP_NAME)] = ::SignalBaseGetString(SIGNAL_BASE_NAME); this.m_string_prop[this.IndexProp(SIGNAL_MQL5_PROP_CURRENCY)] = ::SignalBaseGetString(SIGNAL_BASE_CURRENCY); } //+------------------------------------------------------------------+
以前は、falseで初期化されていました。次に、シグナルオブジェクトIDをアクティブなサブスクリプションを持つ現在のシグナルのIDと比較した結果で初期化します。シグナルにアクティブなサブスクリプションがある場合、それは「現在サブスクライブされている」もので、MQL5.comシグナルデータベースからのシグナルIDを特徴とします。それらが等しい場合、これはサブスクリプションがそのシグナルでアクティブであることを意味します。比較結果はtrueに等しく、そうでない場合はfalseです。
ここで新しいコレクションを開発しているので、そのコレクションのカスタムIDを定義する必要があります。\MQL5\Include\DoEasy\Defines.mqhで、MQL5.comシグナルサービスシグナルコレクションのIDを追加します。
//--- Collection list IDs #define COLLECTION_HISTORY_ID (0x777A) // Historical collection list ID #define COLLECTION_MARKET_ID (0x777B) // Market collection list ID #define COLLECTION_EVENTS_ID (0x777C) // Event collection list ID #define COLLECTION_ACCOUNT_ID (0x777D) // Account collection list ID #define COLLECTION_SYMBOLS_ID (0x777E) // Symbol collection list ID #define COLLECTION_SERIES_ID (0x777F) // Timeseries collection list ID #define COLLECTION_BUFFERS_ID (0x7780) // Indicator buffer collection list ID #define COLLECTION_INDICATORS_ID (0x7781) // Indicator collection list ID #define COLLECTION_INDICATORS_DATA_ID (0x7782) // Indicator data collection list ID #define COLLECTION_TICKSERIES_ID (0x7783) // Tick series collection list ID #define COLLECTION_MBOOKSERIES_ID (0x7784) // DOM series collection list ID #define COLLECTION_MQL5_SIGNALS_ID (0x7785) // MQL5 signals collection list ID //--- Data parameters for file operations
MQL5.comシグナルサービスのシグナルコレクションを使用できるようにするには、シグナルオブジェクトのプロパティで検索および並べ替えるためのメソッドを作成する必要があります。コレクションごとに個別の検索と並べ替えのメソッドが作成されます。すべてのメソッドは互いに同じで、第3部で詳細に説明されています。
\MQL5\Include\DoEasy\Services\Select.mqhのCSelectクラスファイルで、MQL5シグナルオブジェクトクラスファイルをインクルードしてシグナルオブジェクトコレクションを使用するための新しいメソッドを宣言します。
//+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include <Arrays\ArrayObj.mqh> #include "..\Objects\Orders\Order.mqh" #include "..\Objects\Events\Event.mqh" #include "..\Objects\Accounts\Account.mqh" #include "..\Objects\Symbols\Symbol.mqh" #include "..\Objects\PendRequest\PendRequest.mqh" #include "..\Objects\Series\SeriesDE.mqh" #include "..\Objects\Indicators\Buffer.mqh" #include "..\Objects\Indicators\IndicatorDE.mqh" #include "..\Objects\Indicators\DataInd.mqh" #include "..\Objects\Ticks\DataTick.mqh" #include "..\Objects\Book\MarketBookOrd.mqh" #include "..\Objects\MQLSignalBase\MQLSignal.mqh" //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Methods of working with MQL5 signal data | //+------------------------------------------------------------------+ //--- Return the list of MQL5 signals with one of (1) integer, (2) real and (3) string properties meeting a specified criterion static CArrayObj *ByMQLSignalProperty(CArrayObj *list_source,ENUM_SIGNAL_MQL5_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByMQLSignalProperty(CArrayObj *list_source,ENUM_SIGNAL_MQL5_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByMQLSignalProperty(CArrayObj *list_source,ENUM_SIGNAL_MQL5_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Return the MQL5 signal index in the list with the maximum value of the (1) integer, (2) real and (3) string properties static int FindMQLSignalMax(CArrayObj *list_source,ENUM_SIGNAL_MQL5_PROP_INTEGER property); static int FindMQLSignalMax(CArrayObj *list_source,ENUM_SIGNAL_MQL5_PROP_DOUBLE property); static int FindMQLSignalMax(CArrayObj *list_source,ENUM_SIGNAL_MQL5_PROP_STRING property); //--- Return the MQL5 signal in the list with the minimum value of (1) integer, (2) real and (3) string property static int FindMQLSignalMin(CArrayObj *list_source,ENUM_SIGNAL_MQL5_PROP_INTEGER property); static int FindMQLSignalMin(CArrayObj *list_source,ENUM_SIGNAL_MQL5_PROP_DOUBLE property); static int FindMQLSignalMin(CArrayObj *list_source,ENUM_SIGNAL_MQL5_PROP_STRING property); //--- }; //+------------------------------------------------------------------+
クラス本体の外側で実装しましょう。
//+------------------------------------------------------------------+ //| Methods of working with MQL5 signal data | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Return the list of MQL5 signals with one integer | //| property meeting the specified criterion | //+------------------------------------------------------------------+ CArrayObj *CSelect::ByMQLSignalProperty(CArrayObj *list_source,ENUM_SIGNAL_MQL5_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode) { if(list_source==NULL) return NULL; CArrayObj *list=new CArrayObj(); if(list==NULL) return NULL; list.FreeMode(false); ListStorage.Add(list); int total=list_source.Total(); for(int i=0; i<total; i++) { CMQLSignal *obj=list_source.At(i); if(!obj.SupportProperty(property)) continue; long obj_prop=obj.GetProperty(property); if(CompareValues(obj_prop,value,mode)) list.Add(obj); } return list; } //+------------------------------------------------------------------+ //| Return the list of MQL5 signals with one real | //| property meeting the specified criterion | //+------------------------------------------------------------------+ CArrayObj *CSelect::ByMQLSignalProperty(CArrayObj *list_source,ENUM_SIGNAL_MQL5_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode) { if(list_source==NULL) return NULL; CArrayObj *list=new CArrayObj(); if(list==NULL) return NULL; list.FreeMode(false); ListStorage.Add(list); for(int i=0; i<list_source.Total(); i++) { CMQLSignal *obj=list_source.At(i); if(!obj.SupportProperty(property)) continue; double obj_prop=obj.GetProperty(property); if(CompareValues(obj_prop,value,mode)) list.Add(obj); } return list; } //+------------------------------------------------------------------+ //| Return the list of MQL5 signals with one string | //| property meeting the specified criterion | //+------------------------------------------------------------------+ CArrayObj *CSelect::ByMQLSignalProperty(CArrayObj *list_source,ENUM_SIGNAL_MQL5_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode) { if(list_source==NULL) return NULL; CArrayObj *list=new CArrayObj(); if(list==NULL) return NULL; list.FreeMode(false); ListStorage.Add(list); for(int i=0; i<list_source.Total(); i++) { CMQLSignal *obj=list_source.At(i); if(!obj.SupportProperty(property)) continue; string obj_prop=obj.GetProperty(property); if(CompareValues(obj_prop,value,mode)) list.Add(obj); } return list; } //+------------------------------------------------------------------+ //| Return the MQL5 signal index in the list | //| with the maximum integer property value | //+------------------------------------------------------------------+ int CSelect::FindMQLSignalMax(CArrayObj *list_source,ENUM_SIGNAL_MQL5_PROP_INTEGER property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CMQLSignal *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CMQLSignal *obj=list_source.At(i); long obj1_prop=obj.GetProperty(property); max_obj=list_source.At(index); long obj2_prop=max_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i; } return index; } //+------------------------------------------------------------------+ //| Return the MQL5 signal index in the list | //| with the maximum real property value | //+------------------------------------------------------------------+ int CSelect::FindMQLSignalMax(CArrayObj *list_source,ENUM_SIGNAL_MQL5_PROP_DOUBLE property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CMQLSignal *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CMQLSignal *obj=list_source.At(i); double obj1_prop=obj.GetProperty(property); max_obj=list_source.At(index); double obj2_prop=max_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i; } return index; } //+------------------------------------------------------------------+ //| Return the MQL5 signal index in the list | //| with the maximum string property value | //+------------------------------------------------------------------+ int CSelect::FindMQLSignalMax(CArrayObj *list_source,ENUM_SIGNAL_MQL5_PROP_STRING property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CMQLSignal *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CMQLSignal *obj=list_source.At(i); string obj1_prop=obj.GetProperty(property); max_obj=list_source.At(index); string obj2_prop=max_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i; } return index; } //+------------------------------------------------------------------+ //| Return the MQL5 signal index in the list | //| with the minimum integer property value | //+------------------------------------------------------------------+ int CSelect::FindMQLSignalMin(CArrayObj* list_source,ENUM_SIGNAL_MQL5_PROP_INTEGER property) { int index=0; CMQLSignal *min_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CMQLSignal *obj=list_source.At(i); long obj1_prop=obj.GetProperty(property); min_obj=list_source.At(index); long obj2_prop=min_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i; } return index; } //+------------------------------------------------------------------+ //| Return the MQL5 signal index in the list | //| with the minimum real property value | //+------------------------------------------------------------------+ int CSelect::FindMQLSignalMin(CArrayObj* list_source,ENUM_SIGNAL_MQL5_PROP_DOUBLE property) { int index=0; CMQLSignal *min_obj=NULL; int total=list_source.Total(); if(total== 0) return WRONG_VALUE; for(int i=1; i<total; i++) { CMQLSignal *obj=list_source.At(i); double obj1_prop=obj.GetProperty(property); min_obj=list_source.At(index); double obj2_prop=min_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i; } return index; } //+------------------------------------------------------------------+ //| Return the MQL5 signal index in the list | //| with the minimum string property value | //+------------------------------------------------------------------+ int CSelect::FindMQLSignalMin(CArrayObj* list_source,ENUM_SIGNAL_MQL5_PROP_STRING property) { int index=0; CMQLSignal *min_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CMQLSignal *obj=list_source.At(i); string obj1_prop=obj.GetProperty(property); min_obj=list_source.At(index); string obj2_prop=min_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i; } return index; } //+------------------------------------------------------------------+
上記したように、これらすべてのメソッド(各ライブラリオブジェクトクラスで同一)は何度も検討されました。詳細については、第3部を参照してください。
これで、MQL5.comシグナルサービスシグナルオブジェクトのコレクションクラスを開発する準備が整いました。
MQL5シグナルオブジェクトのコレクションクラス
\MQL5\Include\DoEasy\Collections\ライブラリフォルダで、MQLSignalsCollection.mqhに新しいクラスCMQLSignalsCollectionを作成します。
クラスファイルに、作業に必要なすべてのクラスファイルをインクルードします。
//+------------------------------------------------------------------+ //| MQLSignalsCollection.mqh | //| Copyright 2021, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\MQLSignalBase\MQLSignal.mqh" //+------------------------------------------------------------------+
クラスは、すべてのライブラリオブジェクトの基本オブジェクトから派生します。
//+------------------------------------------------------------------+ //| MQL5 signal object collection | //+------------------------------------------------------------------+ class CMQLSignalsCollection : public CBaseObj { }
クラス本体を見て、それが構成するメソッドを分析してみましょう。
//+------------------------------------------------------------------+ //| MQLSignalsCollection.mqh | //| Copyright 2021, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\MQLSignalBase\MQLSignal.mqh" //+------------------------------------------------------------------+ //| MQL5 signal object collection | //+------------------------------------------------------------------+ class CMQLSignalsCollection : public CBaseObj { private: CListObj m_list; // List of MQL5 signal objects int m_signals_base_total; // Number of signals in the MQL5 signal database //--- Subscribe to a signal bool Subscribe(const long signal_id); //--- Set the flag allowing synchronization without confirmation dialog bool CurrentSetConfirmationsDisableFlag(const bool flag); //--- Set the flag of copying Stop Loss and Take Profit bool CurrentSetSLTPCopyFlag(const bool flag); //--- Set the flag allowing the copying of signals by subscription bool CurrentSetSubscriptionEnabledFlag(const bool flag); public: //--- Return (1) itself and (2) the DOM series collection list CMQLSignalsCollection *GetObject(void) { return &this; } CArrayObj *GetList(void) { return &this.m_list; } //--- Return the list by selected (1) integer, (2) real and (3) string properties meeting the compared criterion CArrayObj *GetList(ENUM_SIGNAL_MQL5_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByMQLSignalProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SIGNAL_MQL5_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByMQLSignalProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SIGNAL_MQL5_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByMQLSignalProperty(this.GetList(),property,value,mode); } //--- Return the number of MQL5 signal objects in the list int DataTotal(void) const { return this.m_list.Total(); } //--- Return the pointer to the MQL5 signal object (1) by ID, (2) by name and (3) by index in the list CMQLSignal *GetMQLSignal(const long id); CMQLSignal *GetMQLSignal(const string name); CMQLSignal *GetMQLSignal(const int index) { return this.m_list.At(index); } //--- Create the collection list of MQL5 signal objects bool CreateCollection(void); //--- Update the collection list of MQL5 signal objects void Refresh(const bool messages=true); //--- Display (1) the complete and (2) short collection description in the journal void Print(void); void PrintShort(const bool list=false,const bool paid=true,const bool free=true); //--- Constructor CMQLSignalsCollection(); //--- Subscribe to a signal by (1) ID and (2) signal name bool SubscribeByID(const long signal_id); bool SubscribeByName(const string signal_name); //+----------------------------------------------------------------------------+ //| Methods of working with the current signal the subscription is active for | //+----------------------------------------------------------------------------+ //--- Return the flag allowing working with the signal service bool ProgramIsAllowed(void) { return (bool)::MQLInfoInteger(MQL_SIGNALS_ALLOWED); } //--- Unsubscribe from the current signal bool CurrentUnsubscribe(void); //--- Set the percentage for converting deal volume bool CurrentSetEquityLimit(const double value); //--- Set the market order slippage used when synchronizing positions and copying deals bool CurrentSetSlippage(const double value); //--- Set deposit limitations (in %) bool CurrentSetDepositPercent(const int value); //--- Return the percentage for converting deal volume double CurrentEquityLimit(void) { return ::SignalInfoGetDouble(SIGNAL_INFO_EQUITY_LIMIT); } //--- Return the market order slippage used when synchronizing positions and copying deals double CurrentSlippage(void) { return ::SignalInfoGetDouble(SIGNAL_INFO_SLIPPAGE); } //--- Return the flag allowing synchronization without confirmation dialog bool CurrentConfirmationsDisableFlag(void) { return (bool)::SignalInfoGetInteger(SIGNAL_INFO_CONFIRMATIONS_DISABLED); } //--- Return the flag of copying Stop Loss and Take Profit bool CurrentSLTPCopyFlag(void) { return (bool)::SignalInfoGetInteger(SIGNAL_INFO_COPY_SLTP); } //--- Return deposit limitations (in %) int CurrentDepositPercent(void) { return (int)::SignalInfoGetInteger(SIGNAL_INFO_DEPOSIT_PERCENT); } //--- Return the flag allowing the copying of signals by subscription bool CurrentSubscriptionEnabledFlag(void) { return (bool)::SignalInfoGetInteger(SIGNAL_INFO_SUBSCRIPTION_ENABLED); } //--- Return the limitation by funds for a signal double CurrentVolumePercent(void) { return ::SignalInfoGetDouble(SIGNAL_INFO_VOLUME_PERCENT); } //--- Return the signal ID long CurrentID(void) { return ::SignalInfoGetInteger(SIGNAL_INFO_ID); } //--- Return the flag of agreeing to the terms of use of the Signals service bool CurrentTermsAgreeFlag(void) { return (bool)::SignalInfoGetInteger(SIGNAL_INFO_TERMS_AGREE); } //--- Return the signal name string CurrentName(void) { return ::SignalInfoGetString(SIGNAL_INFO_NAME); } //--- Enable synchronization without the confirmation dialog bool CurrentSetConfirmationsDisableON(void) { return this.CurrentSetConfirmationsDisableFlag(true); } //--- Disable synchronization without the confirmation dialog bool CurrentSetConfirmationsDisableOFF(void){ return this.CurrentSetConfirmationsDisableFlag(false); } //--- Enable copying Stop Loss and Take Profit bool CurrentSetSLTPCopyON(void) { return this.CurrentSetSLTPCopyFlag(true); } //--- Disable copying Stop Loss and Take Profit bool CurrentSetSLTPCopyOFF(void) { return this.CurrentSetSLTPCopyFlag(false); } //--- Enable copying deals by subscription bool CurrentSetSubscriptionEnableON(void) { return this.CurrentSetSubscriptionEnabledFlag(true); } //--- Disable copying deals by subscription bool CurrentSetSubscriptionEnableOFF(void) { return this.CurrentSetSubscriptionEnabledFlag(false); } //--- Return the description of enabling working with signals for the launched program string ProgramIsAllowedDescription(void); //--- Return the percentage description for converting the deal volume string CurrentEquityLimitDescription(void); //--- Return the description of the market order slippage used when synchronizing positions and copying deals string CurrentSlippageDescription(void); //--- Return the description of the limitation by funds for a signal string CurrentVolumePercentDescription(void); //--- Return the description of the flag allowing synchronization without confirmation dialog string CurrentConfirmationsDisableFlagDescription(void); //--- Return the description of the flag of copying Stop Loss and Take Profit string CurrentSLTPCopyFlagDescription(void); //--- Return the description of the deposit limitations (in %) string CurrentDepositPercentDescription(void); //--- Return the description of the flag allowing the copying of signals by subscription string CurrentSubscriptionEnabledFlagDescription(void); //--- Return the description of the signal ID string CurrentIDDescription(void); //--- Return the description of the flag of agreeing to the terms of use of the Signals service string CurrentTermsAgreeFlagDescription(void); //--- Return the description of the signal name string CurrentNameDescription(void); //--- Display the parameters of signal copying settings in the journal void CurrentSubscriptionParameters(void); //--- }; //+------------------------------------------------------------------+
クラスのprivateセクションには、MQL5シグナルオブジェクトを格納するリストオブジェクトと、補助変数およびメソッドがあります。
クラスのpublicセクションには、オブジェクトコレクションリストを使用するための標準的なメソッドと、IDと名前で選択したシグナルをサブスクライブするための2つのメソッドがあります。また、クラスのpublicセクションには、サブスクリプションがアクティブになっている現在のシグナルを使用するためのメソッドがあります。
いくつかのメソッドの実装を見てみましょう。
クラスコンストラクタでコレクションリストをクリア、並び替え済みリストフラグを設定、MQL5シグナルオブジェクトのコレクションのIDをリスト用に設定、 MQL5.comシグナルデータベースにシグナルの総数を書き込み、コレクション作成メソッドを呼び出します。
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CMQLSignalsCollection::CMQLSignalsCollection() { this.m_list.Clear(); this.m_list.Sort(); this.m_list.Type(COLLECTION_MQL5_SIGNALS_ID); this.m_signals_base_total=::SignalBaseTotal(); this.CreateCollection(); } //+------------------------------------------------------------------+
シグナルリストを自動更新したりライブラリを使用して管理したりすることはないため、リストを更新するメソッドで十分です。データベースに存在するすべてのシグナルが読み取られ、メソッドのコレクションリストに送信されます。MQL5.comシグナルデータベースから更新されたシグナルリストを取得する場合は、コレクションからデータを受信する前に、ユーザーが自分でRefresh()更新メソッドを呼び出す必要があります。ただし、とにかくコレクション作成メソッドを使用して、一連の一般的なライブラリコレクションメソッドとの互換性を提供します。メソッド自体は、リストをクリアしてコレクション更新メソッドを呼び出すだけです。コレクション作成メソッドからRefresh()メソッドを最初に呼び出した後、コレクションリストが入力され、処理できるようになります。可能性のある新しいシグナルを検索するためにコレクションリストを更新する必要がある場合は、コレクションリストにアクセスする前にRefresh()メソッドを呼び出すだけです。
以下は、コレクションを作成するメソッドです。
//+------------------------------------------------------------------+ //| Create the collection list of MQL5 signal objects | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::CreateCollection(void) { this.m_list.Clear(); this.Refresh(false); if(m_list.Total()>0) { ::Print(CMessage::Text(MSG_MQLSIG_COLLECTION_TEXT_MQL5_SIGNAL_COLLECTION)," ",CMessage::Text(MSG_LIB_TEXT_TS_TEXT_CREATED_OK)); return true; } return false; } //+------------------------------------------------------------------+
ここでシグナルコレクションリストをクリアし、リストにMQL5.comシグナルデータベースからのシグナルを入力します。コレクションリスト内のシグナルの数がゼロを超える場合(リストに入力される)、コレクションリストが正常に作成されたことに関するメッセージを表示し、trueを返します。
その他の場合はfalseを返します。
以下はコレクションリストを更新するメソッドです。
//+------------------------------------------------------------------+ //| Update the collection list of MQL5 signal objects | //+------------------------------------------------------------------+ void CMQLSignalsCollection::Refresh(const bool messages=true) { this.m_signals_base_total=::SignalBaseTotal(); //--- loop through all signals in the signal database for(int i=0;i<this.m_signals_base_total;i++) { //--- Select a signal from the signal database by the loop index if(!::SignalBaseSelect(i)) continue; //--- Get the current signal ID and //--- create a new MQL5 signal object based on it long id=::SignalBaseGetInteger(SIGNAL_BASE_ID); CMQLSignal *signal=new CMQLSignal(id); if(signal==NULL) continue; //--- Set the sorting flag for the list by signal ID and, //--- if such a signal is already present in the collection list, //--- remove the created object and go to the next loop iteration m_list.Sort(SORT_BY_SIGNAL_MQL5_ID); if(this.m_list.Search(signal)!=WRONG_VALUE) { delete signal; continue; } //--- If failed to add a new signal object to the collection list, //--- remove the created object and go to the next loop iteration if(!this.m_list.InsertSort(signal)) { delete signal; continue; } //--- If an MQL5 signal object is successfully added to the collection //--- and the new object message flag is set in the parameters passed to the method, //--- display a message about a newly found signal else if(messages) { ::Print(DFUN,CMessage::Text(MSG_MQLSIG_COLLECTION_TEXT_SIGNALS_NEW),":"); signal.PrintShort(true); } } } //+------------------------------------------------------------------+
メソッドのロジックについては、コードコメントで詳しく説明されています。つまり、メソッドは、新しく検出されたシグナルを通知する必要があることを示すフラグを受け取ります。このメソッドはコレクションリストをクリアしないため、新しく検出されたシグナルのみを追加できます。メッセージフラグが設定されている場合、新しいシグナルオブジェクトがリストに正常に追加された場合に、操作ログは新しく検出されたシグナルに関するメッセージを表示します。
現在、このメソッドは既存のシグナルのパラメータを更新する機能を備えておらず非常に簡単です。IDによるシグナルオブジェクトへのアクセスとそのプロパティへの新しい値の設定を使用して、プログラムで独自にそれらを更新できます。後で、既存のシグナルパラメータの自動更新を時間ごとに追加します。MQL5.comシグナルコレクションクラスが必要な場合は、新しいシグナルに関するイベントの送信と、追跡されるシグナルのパラメータの変更を実装します。
以下は、シグナルIDによってMQL5シグナルオブジェクトへのポインタを返すメソッドです。
//+------------------------------------------------------------------+ //| Return the pointer to an MQL5 signal object by an ID | //+------------------------------------------------------------------+ CMQLSignal *CMQLSignalsCollection::GetMQLSignal(const long id) { CArrayObj *list=GetList(SIGNAL_MQL5_PROP_ID,id,EQUAL); return(list!=NULL ? list.At(0) : NULL); } //+------------------------------------------------------------------+
シグナルIDでMQL5シグナルオブジェクトのリストを取得し、取得したリストから単一のオブジェクトを返すか、NULLを返します。
以下は、シグナル名でMQL5シグナルオブジェクトへのポインタを返すメソッドです。
//+------------------------------------------------------------------+ //| Return the pointer to an MQL5 signal object by a name | //+------------------------------------------------------------------+ CMQLSignal *CMQLSignalsCollection::GetMQLSignal(const string name) { CArrayObj *list=GetList(SIGNAL_MQL5_PROP_NAME,name,EQUAL); return(list!=NULL ? list.At(0) : NULL); } //+------------------------------------------------------------------+
シグナル名でMQL5シグナルオブジェクトのリストを取得し、取得したリストから単一のオブジェクトを返すか、NULLを返します。
以下は、完全なコレクションリストを操作ログに返すメソッドです。
//+------------------------------------------------------------------+ //| Display complete collection description to the journal | //+------------------------------------------------------------------+ void CMQLSignalsCollection::Print(void) { ::Print(CMessage::Text(MSG_MQLSIG_COLLECTION_TEXT_MQL5_SIGNAL_COLLECTION),":"); for(int i=0;i<this.m_list.Total();i++) { CMQLSignal *signal=this.m_list.At(i); if(signal==NULL) continue; signal.Print(); } } //+------------------------------------------------------------------+
ヘッダーが最初に作成されます。次に、コレクションリストによるループで、次のMQLシグナルオブジェクトを取得し、完全な説明を表示します。
以下は、短いコレクションリストを操作ログに返すメソッドです。
//+------------------------------------------------------------------+ //| Display the short collection description in the journal | //+------------------------------------------------------------------+ void CMQLSignalsCollection::PrintShort(const bool list=false,const bool paid=true,const bool free=true) { //--- Display the header in the journal ::Print(CMessage::Text(MSG_MQLSIG_COLLECTION_TEXT_MQL5_SIGNAL_COLLECTION),":"); //--- If the list is full, display short descriptions of all signals in the collection //--- according to the flags indicating the necessity to display paid and free signals if(list) for(int i=0;i<this.m_list.Total();i++) { CMQLSignal *signal=this.m_list.At(i); if(signal==NULL || (signal.Price()>0 && !paid) || (signal.Price()==0 && !free)) continue; signal.PrintShort(true); } //--- If not the signal list else { //--- Sort the list by signal price this.m_list.Sort(SORT_BY_SIGNAL_MQL5_PRICE); //--- Get the list of free signals and their number CArrayObj *list_free=this.GetList(SIGNAL_MQL5_PROP_PRICE,0,EQUAL); int num_free=(list_free==NULL ? 0 : list_free.Total()); //--- Sort the list by signal price this.m_list.Sort(SORT_BY_SIGNAL_MQL5_PRICE); //--- Get the list of paid signals and their number CArrayObj *list_paid=this.GetList(SIGNAL_MQL5_PROP_PRICE,0,MORE); int num_paid=(list_paid==NULL ? 0 : list_paid.Total()); //--- Display the number of free and paid signals in the collection in the journal ::Print ( "- ",CMessage::Text(MSG_MQLSIG_COLLECTION_TEXT_SIGNALS_FREE),": ",(string)num_free, ", ",CMessage::Text(MSG_MQLSIG_COLLECTION_TEXT_SIGNALS_PAID),": ",(string)num_paid ); } } //+------------------------------------------------------------------+
渡されたフラグに応じて、メソッドは操作ログにさまざまなメッセージとリストを表示します。
ヘッダーが最初に来ます。リストフラグが設定されている場合、操作ログにはコレクションからの信号の簡単な説明が表示されます。有料および無料シグナルのフラグが考慮されます。操作ログには、ステータスに応じて、すべてのシグナル、有料のシグナルのみ、または無料のシグナルのみが表示されます。
説明をリストとしてではなく表示する必要がある場合、ヘッダーの後に、コレクションリスト内の無料および有料のシグナルの総数が続きます。
以下は、シグナルをサブスクライブするメソッド(privateメソッド)とシグナルをサブスクライブしないメソッド(publicメソッド)です。
//+------------------------------------------------------------------+ //| Subscribe to a signal | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::Subscribe(const long signal_id) { //--- If working with signals is disabled for a program, //--- display the appropriate message and the recommendation to check the program settings if(!this.ProgramIsAllowed()) { ::Print(DFUN,CMessage::Text(MSG_SIGNAL_INFO_ERR_SIGNAL_NOT_ALLOWED)); ::Print(DFUN,CMessage::Text(MSG_SIGNAL_INFO_TEXT_CHECK_SETTINGS)); return false; } //--- If failed to subscribe to a signal, display the error message and return 'false' ::ResetLastError(); if(!::SignalSubscribe(signal_id)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Subscription successful. Display the successful signal subscription message and return 'true' ::Print(CMessage::Text(MSG_SIGNAL_INFO_TEXT_SIGNAL_SUBSCRIBED)," ID ",(string)this.CurrentID()," \"",CurrentName(),"\""); return true; } //+------------------------------------------------------------------+ //| Unsubscribe from a subscribed signal | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::CurrentUnsubscribe(void) { //--- If working with signals is disabled for a program, //--- display the appropriate message and the recommendation to check the program settings if(!this.ProgramIsAllowed()) { ::Print(DFUN,CMessage::Text(MSG_SIGNAL_INFO_ERR_SIGNAL_NOT_ALLOWED)); ::Print(DFUN,CMessage::Text(MSG_SIGNAL_INFO_TEXT_CHECK_SETTINGS)); return false; } //--- Remember an ID and a name of the current signal ::ResetLastError(); long id=this.CurrentID(); string name=this.CurrentName(); //--- If the ID is zero (no subscription), return 'true' if(id==0) return true; //--- If failed to unsubscribe from a signal, display the error message and return 'false' if(!::SignalUnsubscribe()) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Unsubscribed from a signal successfully. Display the message about successfully unsubscribing from a signal and return 'true' ::Print(CMessage::Text(MSG_SIGNAL_INFO_TEXT_SIGNAL_UNSUBSCRIBED)," ID ",(string)id," \"",name,"\""); return true; } //+------------------------------------------------------------------+
メソッドのロジックについては、メソッドリストで詳しく説明しています。
以下は、シグナルIDによってシグナルのサブスクリプションを実行するpublicメソッドです。
//+------------------------------------------------------------------+ //| Subscribe to a signal by ID | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::SubscribeByID(const long signal_id) { CMQLSignal *signal=GetMQLSignal(signal_id); if(signal==NULL) { ::Print(DFUN,CMessage::Text(MSG_MQLSIG_COLLECTION_ERR_FAILED_GET_SIGNAL),": ",signal_id); return false; } return this.Subscribe(signal.ID()); } //+------------------------------------------------------------------+
ここで、メソッドに渡されたIDによってコレクションリスト内のMQL5シグナルオブジェクトへのポインタを取得し、上記で検討したprivateシグナルサブスクリプションメソッドの結果を返します。
以下は、シグナル名でシグナルのサブスクリプションを実行するpublicメソッドです。
//+------------------------------------------------------------------+ //| Subscribe to a signal by signal name | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::SubscribeByName(const string signal_name) { CMQLSignal *signal=GetMQLSignal(signal_name); if(signal==NULL) { ::Print(DFUN,CMessage::Text(MSG_MQLSIG_COLLECTION_ERR_FAILED_GET_SIGNAL),": \"",signal_name,"\""); return false; } return this.Subscribe(signal.ID()); } //+------------------------------------------------------------------+
ここで、メソッドに渡されたシグナル名によってコレクションリスト内のMQL5シグナルオブジェクトへのポインタ(名前は事前に知っている必要があります)および return 上記で検討したprivateシグナルサブスクリプションメソッドの結果を取得します。
以下は、取引シグナルをコピーする値を設定するメソッドです。
//+------------------------------------------------------------------+ //| Set the percentage for converting a deal volume | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::CurrentSetEquityLimit(const double value) { ::ResetLastError(); if(!::SignalInfoSetDouble(SIGNAL_INFO_EQUITY_LIMIT,value)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } return true; } //+------------------------------------------------------------------+ //| Define the slippage used to set | //| market orders when synchronizing positions and copying deals | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::CurrentSetSlippage(const double value) { ::ResetLastError(); if(!::SignalInfoSetDouble(SIGNAL_INFO_SLIPPAGE,value)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } return true; } //+------------------------------------------------------------------+ //| Set the flag enabling synchronization | //| without confirmation dialog | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::CurrentSetConfirmationsDisableFlag(const bool flag) { ::ResetLastError(); if(!::SignalInfoSetInteger(SIGNAL_INFO_CONFIRMATIONS_DISABLED,flag)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } return true; } //+------------------------------------------------------------------+ //| Set the flag of copying Stop Loss and Take Profit | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::CurrentSetSLTPCopyFlag(const bool flag) { ::ResetLastError(); if(!::SignalInfoSetInteger(SIGNAL_INFO_COPY_SLTP,flag)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } return true; } //+------------------------------------------------------------------+ //| Set deposit limitations (in %) | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::CurrentSetDepositPercent(const int value) { ::ResetLastError(); if(!::SignalInfoSetInteger(SIGNAL_INFO_DEPOSIT_PERCENT,value)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } return true; } //+------------------------------------------------------------------+ //| Set the flag allowing the copying of signals by subscription | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::CurrentSetSubscriptionEnabledFlag(const bool flag) { ::ResetLastError(); if(!::SignalInfoSetInteger(SIGNAL_INFO_SUBSCRIPTION_ENABLED,flag)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } return true; } //+------------------------------------------------------------------+
ここでは、値を設定するためのSignalInfoSetDouble()およびSignalInfoSetInteger()関数がすべてのメソッドで使用されています。値の設定に失敗した場合、メソッドはエラーの説明を表示し、falseを返します。設定が成功すると、メソッドはtrueを返します。
以下は、取引シグナルのコピーを設定するためのパラメータの説明を返すメソッドです。
//+------------------------------------------------------------------+ //| Return the description of the permission to work with signals | //| for the currently launched program | //+------------------------------------------------------------------+ string CMQLSignalsCollection::ProgramIsAllowedDescription(void) { return ( CMessage::Text(MSG_SIGNAL_INFO_SIGNALS_PERMISSION)+": "+ (this.ProgramIsAllowed() ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ); } //+------------------------------------------------------------------+ //| Return the percentage description for converting the deal volume | //+------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentEquityLimitDescription(void) { return CMessage::Text(MSG_SIGNAL_INFO_EQUITY_LIMIT)+": "+::DoubleToString(this.CurrentEquityLimit(),2)+"%"; } //+------------------------------------------------------------------+ //| Return the description of the slippage used to set | //| market orders when synchronizing positions and copying deals | //+------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentSlippageDescription(void) { return CMessage::Text(MSG_SIGNAL_INFO_SLIPPAGE)+": "+CMessage::Text(MSG_LIB_TEXT_BAR_SPREAD)+" * "+::DoubleToString(this.CurrentSlippage(),2); } //+------------------------------------------------------------------+ //| Return the description of the limitation by funds for a signal | //+------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentVolumePercentDescription(void) { return CMessage::Text(MSG_SIGNAL_INFO_VOLUME_PERCENT)+": "+::DoubleToString(this.CurrentVolumePercent(),2)+"%"; } //+------------------------------------------------------------------+ //| Return the description of the flag enabling synchronization | //| without confirmation dialog | //+------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentConfirmationsDisableFlagDescription(void) { return ( CMessage::Text(MSG_SIGNAL_INFO_CONFIRMATIONS_DISABLED)+": "+ (this.CurrentConfirmationsDisableFlag() ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ); } //+----------------------------------------------------------------------------+ //| Return the description of the flag of copying Stop Loss and Take Profit | //+----------------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentSLTPCopyFlagDescription(void) { return ( CMessage::Text(MSG_SIGNAL_INFO_COPY_SLTP)+": "+ (this.CurrentSLTPCopyFlag() ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ); } //+------------------------------------------------------------------+ //| Return the description of the deposit limitations (in %) | //+------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentDepositPercentDescription(void) { return CMessage::Text(MSG_SIGNAL_INFO_DEPOSIT_PERCENT)+": "+(string)this.CurrentDepositPercent()+"%"; } //+------------------------------------------------------------------+ //| Return the description of the flag enabling | //| deal copying by subscription | //+------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentSubscriptionEnabledFlagDescription(void) { return ( CMessage::Text(MSG_SIGNAL_INFO_SUBSCRIPTION_ENABLED)+": "+ (this.CurrentSubscriptionEnabledFlag() ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ); } //+------------------------------------------------------------------+ //| Return the signal ID description | //+------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentIDDescription(void) { return CMessage::Text(MSG_SIGNAL_INFO_ID)+": "+(this.CurrentID()>0 ? (string)this.CurrentID() : CMessage::Text(MSG_LIB_PROP_EMPTY)); } //+------------------------------------------------------------------+ //| Return the description of the flag indicating | //| consent to the terms of use of the Signals service | //+------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentTermsAgreeFlagDescription(void) { return ( CMessage::Text(MSG_SIGNAL_INFO_TERMS_AGREE)+": "+ (this.CurrentTermsAgreeFlag() ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ); } //+------------------------------------------------------------------+ //| Return the description of the signal name | //+------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentNameDescription(void) { return CMessage::Text(MSG_SIGNAL_INFO_NAME)+": "+(this.CurrentName()!="" ? this.CurrentName() : CMessage::Text(MSG_LIB_PROP_EMPTY)); } //+------------------------------------------------------------------+
パラメータの説明ヘッダーとその現在の値を特徴とする文字列は、各メソッドで作成されます。
以下は、操作ログの取引シグナルコピー設定のパラメータを表示するメソッドです。
//+------------------------------------------------------------------+ //| Display the parameters of signal copying settings in the journal | //+------------------------------------------------------------------+ void CMQLSignalsCollection::CurrentSubscriptionParameters(void) { ::Print("============= ",CMessage::Text(MSG_SIGNAL_INFO_PARAMETERS)," ============="); ::Print(this.ProgramIsAllowedDescription()); ::Print(this.CurrentTermsAgreeFlagDescription()); ::Print(this.CurrentSubscriptionEnabledFlagDescription()); ::Print(this.CurrentConfirmationsDisableFlagDescription()); ::Print(this.CurrentSLTPCopyFlagDescription()); ::Print(this.CurrentSlippageDescription()); ::Print(this.CurrentEquityLimitDescription()); ::Print(this.CurrentDepositPercentDescription()); ::Print(this.CurrentVolumePercentDescription()); ::Print(this.CurrentIDDescription()); ::Print(this.CurrentNameDescription()); ::Print(""); } //+------------------------------------------------------------------+
ヘッダーが最初に表示され、次にすべての取引シグナルコピーパラメータが1つずつ表示されます。パラメータは、上記で検討した適切なメソッドによって返されます。
これで、MQL5シグナルオブジェクトコレクションクラスの作成は完了です。
後で改善するかもしれませんが、需要が高いかどうかを判断できるようになるまで、今はこのままにしておきます。
取引シグナル収集クラスを「外界」に接続するには、それらを操作するためのメソッドの開発を、\MQL5\Include\DoEasy\Engine.mqhCEngineライブラリメインオブジェクトクラスに完了する必要があります。
取引シグナルコレクションクラスのファイルをCEngineオブジェクトクラスファイルに収集し、MQL5シグナルコレクションクラスオブジェクトを宣言します。
//+------------------------------------------------------------------+ //| Engine.mqh | //| Copyright 2020, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Services\TimerCounter.mqh" #include "Collections\HistoryCollection.mqh" #include "Collections\MarketCollection.mqh" #include "Collections\EventsCollection.mqh" #include "Collections\AccountsCollection.mqh" #include "Collections\SymbolsCollection.mqh" #include "Collections\ResourceCollection.mqh" #include "Collections\TimeSeriesCollection.mqh" #include "Collections\BuffersCollection.mqh" #include "Collections\IndicatorsCollection.mqh" #include "Collections\TickSeriesCollection.mqh" #include "Collections\BookSeriesCollection.mqh" #include "Collections\MQLSignalsCollection.mqh" #include "TradingControl.mqh" //+------------------------------------------------------------------+ //| Library basis class | //+------------------------------------------------------------------+ class CEngine { private: CHistoryCollection m_history; // Collection of historical orders and deals CMarketCollection m_market; // Collection of market orders and deals CEventsCollection m_events; // Event collection CAccountsCollection m_accounts; // Account collection CSymbolsCollection m_symbols; // Symbol collection CTimeSeriesCollection m_time_series; // Timeseries collection CBuffersCollection m_buffers; // Collection of indicator buffers CIndicatorsCollection m_indicators; // Indicator collection CTickSeriesCollection m_tick_series; // Collection of tick series CMBookSeriesCollection m_book_series; // Collection of DOM series CMQLSignalsCollection m_signals_mql5; // Collection of MQL5.com Signals service signals CResourceCollection m_resource; // Resource list CTradingControl m_trading; // Trading management object CPause m_pause; // Pause object CArrayObj m_list_counters; // List of timer counters
クラスのpublicセクションで、宣言とDOMスナップショットのコレクションクラスを使用するための新しいメソッドと取引シグナルコレクションを使用するためのメソッドを実装します。
//--- Update the DOM series of a specified symbol void MBookSeriesRefresh(const string symbol,const long time_msc) { this.m_book_series.Refresh(symbol,time_msc); } //--- Return (1) the DOM series of a specified symbol, the DOM (2) by index and (3) by time in milliseconds CMBookSeries *GetMBookSeries(const string symbol) { return this.m_book_series.GetMBookseries(symbol); } CMBookSnapshot *GetMBook(const string symbol,const int index) { return this.m_book_series.GetMBook(symbol,index); } CMBookSnapshot *GetMBook(const string symbol,const long time_msc) { return this.m_book_series.GetMBook(symbol,time_msc);} //--- Return the volume of a (1) buy and (2) sell DOM specified by symbol and index long MBookVolumeBuy(const string symbol,const int index); long MBookVolumeSell(const string symbol,const int index); //--- Return the increased precision volume of a (1) buy and (2) sell DOM specified by symbol and index double MBookVolumeBuyReal(const string symbol,const int index); double MBookVolumeSellReal(const string symbol,const int index); //--- Return the volume of a (1) buy and (2) sell DOM specified by symbol and time in milliseconds long MBookVolumeBuy(const string symbol,const long time_msc); long MBookVolumeSell(const string symbol,const long time_msc); //--- Return the increased precision volume of a (1) buy and (2) sell DOM specified by symbol and time in milliseconds double MBookVolumeBuyReal(const string symbol,const long time_msc); double MBookVolumeSellReal(const string symbol,const long time_msc); //--- Return (1) the collection of mql5.com Signals service signals and (2) the list of signals from the mql5.com Signals service signal collection CMQLSignalsCollection *GetSignalsMQL5Collection(void) { return &this.m_signals_mql5; } CArrayObj *GetListSignalsMQL5(void) { return this.m_signals_mql5.GetList(); } //--- Return the list of (1) paid and (2) free signals CArrayObj *GetListSignalsMQL5Paid(void) { return this.m_signals_mql5.GetList(SIGNAL_MQL5_PROP_PRICE,0,MORE); } CArrayObj *GetListSignalsMQL5Free(void) { return this.m_signals_mql5.GetList(SIGNAL_MQL5_PROP_PRICE,0,EQUAL);} //--- (1) Create and (2) update the collection of mql5.com Signals service signals bool SignalsMQL5Create(void) { return this.m_signals_mql5.CreateCollection(); } void SignalsMQL5Refresh(void) { this.m_signals_mql5.Refresh(); } //--- Subscribe to a signal by (1) ID and (2) signal name bool SignalsMQL5Subscribe(const long signal_id) { return this.m_signals_mql5.SubscribeByID(signal_id);} bool SignalsMQL5Subscribe(const string signal_name) { return this.m_signals_mql5.SubscribeByName(signal_name);} //--- Unsubscribe from the current signal bool SignalsMQL5Unsubscribe(void) { return this.m_signals_mql5.CurrentUnsubscribe(); } //--- Return (1) ID and (2) the name of the current signal subscription is performed to long SignalsMQL5CurrentID(void) { return this.m_signals_mql5.CurrentID(); } string SignalsMQL5CurrentName(void) { return this.m_signals_mql5.CurrentName(); } //--- Set the percentage for converting deal volume bool SignalsMQL5CurrentSetEquityLimit(const double value) { return this.m_signals_mql5.CurrentSetEquityLimit(value); } //--- Set the market order slippage used when synchronizing positions and copying deals bool SignalsMQL5CurrentSetSlippage(const double value) { return this.m_signals_mql5.CurrentSetSlippage(value); } //--- Set deposit limitations (in %) bool SignalsMQL5CurrentSetDepositPercent(const int value) { return this.m_signals_mql5.CurrentSetDepositPercent(value); } //--- Enable synchronization without the confirmation dialog bool SignalsMQL5CurrentSetConfirmationsDisableON(void) { return this.m_signals_mql5.CurrentSetConfirmationsDisableON();} //--- Disable synchronization without the confirmation dialog bool SignalsMQL5CurrentSetConfirmationsDisableOFF(void) { return this.m_signals_mql5.CurrentSetConfirmationsDisableOFF();} //--- Enable copying Stop Loss and Take Profit bool SignalsMQL5CurrentSetSLTPCopyON(void) { return this.m_signals_mql5.CurrentSetSLTPCopyON(); } //--- Disable copying Stop Loss and Take Profit bool SignalsMQL5CurrentSetSLTPCopyOFF(void) { return this.m_signals_mql5.CurrentSetSLTPCopyOFF(); } //--- Enable copying deals by subscription bool SignalsMQL5CurrentSetSubscriptionEnableON(void) { return this.m_signals_mql5.CurrentSetSubscriptionEnableON(); } //--- Disable copying deals by subscription bool SignalsMQL5CurrentSetSubscriptionEnableOFF(void) { return this.m_signals_mql5.CurrentSetSubscriptionEnableOFF();} //--- Display (1) the complete, (2) short collection description in the journal and (3) parameters of the signal copying settings void SignalsMQL5Print(void) { m_signals_mql5.Print(); } void SignalsMQL5PrintShort(const bool list=false,const bool paid=true,const bool free=true) { m_signals_mql5.PrintShort(list,paid,free); } void SignalsMQL5CurrentSubscriptionParameters(void) { this.m_signals_mql5.CurrentSubscriptionParameters();} //--- Return (1) the buffer collection and (2) the buffer list from the collection
実装されたメソッドは、同じ名前の対応するコレクションのメソッドを呼び出した結果を返します。
指定されたDOMスナップショットの指定されたボリュームを返すメソッドの実装を見てみましょう。
//+------------------------------------------------------------------+ //| Return the buy volume of a DOM | //| specified by symbol and index | //+------------------------------------------------------------------+ long CEngine::MBookVolumeBuy(const string symbol,const int index) { CMBookSnapshot *mbook=this.GetMBook(symbol,index); return(mbook!=NULL ? mbook.VolumeBuy() : 0); } //+------------------------------------------------------------------+ //| Return the sell volume of a DOM | //| specified by symbol and index | //+------------------------------------------------------------------+ long CEngine::MBookVolumeSell(const string symbol,const int index) { CMBookSnapshot *mbook=this.GetMBook(symbol,index); return(mbook!=NULL ? mbook.VolumeSell() : 0); } //+------------------------------------------------------------------+ //| Return the extended accuracy buy volume | //| of a DOM specified by symbol and index | //+------------------------------------------------------------------+ double CEngine::MBookVolumeBuyReal(const string symbol,const int index) { CMBookSnapshot *mbook=this.GetMBook(symbol,index); return(mbook!=NULL ? mbook.VolumeBuyReal() : 0); } //+------------------------------------------------------------------+ //| Return the extended accuracy sell volume | //| of a DOM specified by symbol and index | //+------------------------------------------------------------------+ double CEngine::MBookVolumeSellReal(const string symbol,const int index) { CMBookSnapshot *mbook=this.GetMBook(symbol,index); return(mbook!=NULL ? mbook.VolumeSellReal() : 0); } //+------------------------------------------------------------------+ //| Return the buy volume of a DOM | //| specified by symbol and time in milliseconds | //+------------------------------------------------------------------+ long CEngine::MBookVolumeBuy(const string symbol,const long time_msc) { CMBookSnapshot *mbook=this.GetMBook(symbol,time_msc); return(mbook!=NULL ? mbook.VolumeBuy() : 0); } //+------------------------------------------------------------------+ //| Return the sell volume of a DOM | //| specified by symbol and time in milliseconds | //+------------------------------------------------------------------+ long CEngine::MBookVolumeSell(const string symbol,const long time_msc) { CMBookSnapshot *mbook=this.GetMBook(symbol,time_msc); return(mbook!=NULL ? mbook.VolumeSell() : 0); } //+------------------------------------------------------------------+ //| Return the extended accuracy buy volume | //| of a DOM specified by symbol and time in milliseconds | //+------------------------------------------------------------------+ double CEngine::MBookVolumeBuyReal(const string symbol,const long time_msc) { CMBookSnapshot *mbook=this.GetMBook(symbol,time_msc); return(mbook!=NULL ? mbook.VolumeBuyReal() : 0); } //+------------------------------------------------------------------+ //| Return the extended accuracy sell volume | //| of a DOM specified by symbol and time in milliseconds | //+------------------------------------------------------------------+ double CEngine::MBookVolumeSellReal(const string symbol,const long time_msc) { CMBookSnapshot *mbook=this.GetMBook(symbol,time_msc); return(mbook!=NULL ? mbook.VolumeSellReal() : 0); } //+------------------------------------------------------------------+
すべてがシンプルです。すべてのメソッドの背後にあるロジックは同じです。最初に、銘柄とインデックスまたは以前に実装されたGetMBook()メソッドを使用したミリ秒単位の時間によってコレクションリストからDOMスナップショットオブジェクトを取得します。次に取得したDOMスナップショットオブジェクトに対応するDOMボリュームを返すまたはオブジェクトの取得に失敗した場合はゼロを返します。
改善と変更点は今のところこれですべてです。
検証
MQL5.comシグナルコレクションの作成をテストしてみましょう。テストは次のように実行されます。
シグナルデータベースから完全なリストを取得し、無料のシグナルのみのリストを表示し、リスト内で最も収益性の高いシグナルを見つけてサブスクライブします。サブスクリプションが成功すると、現在のシグナルのパラメータと、サブスクリプション時に設定された取引シグナルをコピーするためのパラメータが表示されます。次のティックで現在のシグナルのサブスクライブを解除します。
テストを実行するには、前の記事の EAを使用して、\MQL5\Experts\TestDoEasy\Part66\にTestDoEasyPart66.mq5として保存します。
EA入力のリストには、ユーザがEAでMQL5.comシグナルサービスの操作を選択できるようにする設定があります。
//--- input variables input ushort InpMagic = 123; // Magic number input double InpLots = 0.1; // Lots input uint InpStopLoss = 150; // StopLoss in points input uint InpTakeProfit = 150; // TakeProfit in points input uint InpDistance = 50; // Pending orders distance (points) input uint InpDistanceSL = 50; // StopLimit orders distance (points) input uint InpDistancePReq = 50; // Distance for Pending Request's activate (points) input uint InpBarsDelayPReq = 5; // Bars delay for Pending Request's activate (current timeframe) input uint InpSlippage = 5; // Slippage in points input uint InpSpreadMultiplier = 1; // Spread multiplier for adjusting stop-orders by StopLevel input uchar InpTotalAttempts = 5; // Number of trading attempts sinput double InpWithdrawal = 10; // Withdrawal funds (in tester) sinput uint InpButtShiftX = 0; // Buttons X shift sinput uint InpButtShiftY = 10; // Buttons Y shift input uint InpTrailingStop = 50; // Trailing Stop (points) input uint InpTrailingStep = 20; // Trailing Step (points) input uint InpTrailingStart = 0; // Trailing Start (points) input uint InpStopLossModify = 20; // StopLoss for modification (points) input uint InpTakeProfitModify = 60; // TakeProfit for modification (points) sinput ENUM_SYMBOLS_MODE InpModeUsedSymbols = SYMBOLS_MODE_CURRENT; // Mode of used symbols list sinput string InpUsedSymbols = "EURUSD,AUDUSD,EURAUD,EURCAD,EURGBP,EURJPY,EURUSD,GBPUSD,NZDUSD,USDCAD,USDJPY"; // List of used symbols (comma - separator) sinput ENUM_TIMEFRAMES_MODE InpModeUsedTFs = TIMEFRAMES_MODE_LIST; // Mode of used timeframes list sinput string InpUsedTFs = "M1,M5,M15,M30,H1,H4,D1,W1,MN1"; // List of used timeframes (comma - separator) sinput ENUM_INPUT_YES_NO InpUseBook = INPUT_YES; // Use Depth of Market sinput ENUM_INPUT_YES_NO InpUseMqlSignals = INPUT_YES; // Use signal service sinput ENUM_INPUT_YES_NO InpUseSounds = INPUT_YES; // Use sounds //--- global variables
前回の記事では、シグナルの操作に関するすべてのチェックは、EAのOnInit()ハンドラで行われました。今日は、OnTick()で作業します。
したがって、不要なテストコードブロックをOnInit()ハンドラから削除しましょう。
CArrayObj *list=new CArrayObj(); if(list!=NULL) { //--- request the total number of signals in the signal database int total=SignalBaseTotal(); //--- loop through all signals for(int i=0;i<total;i++) { //--- select a signal for further operation if(!SignalBaseSelect(i)) continue; long id=SignalBaseGetInteger(SIGNAL_BASE_ID); CMQLSignal *signal=new CMQLSignal(id); if(signal==NULL) continue; if(!list.Add(signal)) { delete signal; continue; } } //--- display all profitable free signals with a non-zero number of subscribers Print(""); static bool done=false; for(int i=0;i<list.Total();i++) { CMQLSignal *signal=list.At(i); if(signal==NULL) continue; if(signal.Price()>0 || signal.Subscribers()==0) continue; //--- The very first suitable signal is fully displayed in the journal if(!done) { signal.Print(); done=true; } //--- Short descriptions are displayed for the rest else signal.PrintShort(); } delete list; } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
OnTick()ハンドラに、このセクションの冒頭で説明したすべてのテスト条件を満たす新しいテストコードブロックを作成します。
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Remove EA graphical objects by an object name prefix ObjectsDeleteAll(0,prefix); Comment(""); //--- Deinitialize library engine.OnDeinit(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Handle the NewTick event in the library engine.OnTick(rates_data); //--- If working in the tester if(MQLInfoInteger(MQL_TESTER)) { engine.OnTimer(rates_data); // Working in the timer PressButtonsControl(); // Button pressing control engine.EventsHandling(); // Working with events } //--- If the trailing flag is set if(trailing_on) { TrailingPositions(); // Trailing positions TrailingOrders(); // Trailing pending orders } //--- Search for available signals in the database and check the ability to subscribe to a signal by its name static bool done=false; //--- If the first launch and working with signals is enabled in EA custom settings if(InpUseMqlSignals && !done) { //--- Display the list of all free signals in the journal Print(""); engine.GetSignalsMQL5Collection().PrintShort(true,false,true); //--- Get the list of free signals CArrayObj *list=engine.GetListSignalsMQL5Free(); //--- If the list is obtained if(list!=NULL) { //--- Find a signal with the maximum growth in % in the list int index_max_gain=CSelect::FindMQLSignalMax(list,SIGNAL_MQL5_PROP_GAIN); CMQLSignal *signal_max_gain=list.At(index_max_gain); //--- If the signal is found if(signal_max_gain!=NULL) { //--- Display the full signal description in the journal signal_max_gain.Print(); //--- If managed to subscribe to a signal if(engine.SignalsMQL5Subscribe(signal_max_gain.ID())) { //--- Set subscription parameters //--- Enable copying deals by subscription engine.SignalsMQL5CurrentSetSubscriptionEnableON(); //--- Set synchronization without the confirmation dialog engine.SignalsMQL5CurrentSetConfirmationsDisableOFF(); //--- Set copying Stop Loss and Take Profit engine.SignalsMQL5CurrentSetSLTPCopyON(); //--- Set the market order slippage used when synchronizing positions and copying deals engine.SignalsMQL5CurrentSetSlippage(2); //--- Set the percentage for converting deal volume engine.SignalsMQL5CurrentSetEquityLimit(50); //--- Set deposit limitations (in %) engine.SignalsMQL5CurrentSetDepositPercent(70); //--- Display subscription parameters in the journal engine.SignalsMQL5CurrentSubscriptionParameters(); } } } done=true; return; } //--- If a signal subscription is active, unsubscribe if(engine.SignalsMQL5CurrentID()>0) { engine.SignalsMQL5Unsubscribe(); } //--- } //+------------------------------------------------------------------+
新しいコードブロック全体が詳細にコメント化されています。質問がある場合は、コメントで質問してください。
OnInitDoEasy()ライブラリ初期化関数で、コードブロックを追加して、取引シグナルのコレクションリストを作成し、サブスクリプションによる取引シグナルのコピーを可能にするフラグを設定します。
//--- Create tick series of all used symbols engine.TickSeriesCreateAll(); //--- Check created tick series - display descriptions of all created tick series in the journal engine.GetTickSeriesCollection().Print(); //--- Check created DOM series - display descriptions of all created DOM series in the journal engine.GetMBookSeriesCollection().Print(); //--- Create the collection of mql5.com Signals service signals //--- If working with signals is enabled and the signal collection is created if(InpUseMqlSignals && engine.SignalsMQL5Create()) { //--- Enable copying deals by subscription engine.SignalsMQL5CurrentSetSubscriptionEnableON(); //--- Check created MQL5 signal objects of the Signals service - display the short collection description in the journal engine.SignalsMQL5PrintShort(); } //--- If working with signals is not enabled or failed to create the signal collection, //--- disable copying deals by subscription else engine.SignalsMQL5CurrentSetSubscriptionEnableOFF(); //--- Create resource text files
現在の銘柄/時間枠での作業を事前に設定し、MQL5.comシグナルサービスの取引シグナルでの作業のフラグをアクティブにしながら、EAをコンパイルして銘柄チャートで起動します。
EA設定ウィンドウの[共通]タブで、[シグナル設定の変更を許可する]をオンにします。
そうしないと、EAはMQL5.comシグナルを処理できなくなります。
EAを起動した後、操作ログはシグナルコレクションの作成の成功とその簡単な説明に関するメッセージを表示します。
Collection of MQL5.com Signals service signals created successfully Collection of MQL5.com Signals service signals: - Free signals: 195, Paid signals: 805
次に、無料シグナルの完全なリストが表示されます。多数あるので、ここでは例としてそれらの一部のみを示します。
Collection of MQL5.com Signals service signals: - Signal "GBPUSD EXPERT 23233". Author login: mbt_trader, ID 919099, Growth: 3.30, Drawdown: 11.92, Price: 0.00, Subscribers: 0 - Signal "Willian". Author login: Desg, ID 917396, Growth: 12.69, Drawdown: 15.50, Price: 0.00, Subscribers: 0 - Signal "VahidVHZ1366". Author login: 39085485, ID 921427, Growth: 34.36, Drawdown: 12.84, Price: 0.00, Subscribers: 0 - Signal "Vikings". Author login: Myxx, ID 921040, Growth: 7.05, Drawdown: 2.22, Price: 0.00, Subscribers: 2 - Signal "VantageFX Sunphone Dragon". Author login: sunphone, ID 916421, Growth: 537.89, Drawdown: 39.06, Price: 0.00, Subscribers: 21 - Signal "Forex money maker free". Author login: Yggdrasills, ID 916328, Growth: 44.66, Drawdown: 61.15, Price: 0.00, Subscribers: 0 ... ... ... - Signal "Nine Pairs ST". Author login: ebi.pilehvar, ID 935603, Growth: 25.92, Drawdown: 26.41, Price: 0.00, Subscribers: 2 - Signal "FBS140". Author login: mohammeeeedali, ID 949720, Growth: 42.14, Drawdown: 23.11, Price: 0.00, Subscribers: 2 - Signal "StopTheFourthAddition". Author login: pinheirodps, ID 934990, Growth: 41.78, Drawdown: 28.03, Price: 0.00, Subscribers: 2 - Signal "The art of Forex". Author login: Myxx, ID 801685, Growth: 196.39, Drawdown: 40.95, Price: 0.00, Subscribers: 59 - Signal "Bongsanmaskdance1803". Author login: kim25801863, ID 936062, Growth: 12.53, Drawdown: 10.31, Price: 0.00, Subscribers: 0 - Signal "Prospector Scalper EA". Author login: robots4forex, ID 435626, Growth: 334.76, Drawdown: 43.93, Price: 0.00, Subscribers: 215 - Signal "ADS MT5". Author login: vluxus, ID 478235, Growth: 295.68, Drawdown: 40.26, Price: 0.00, Subscribers: 92
次に、検出されたシグナルの完全な説明(最大増加率(%)と成功したサブスクリプションメッセー)を取得します。
============= Beginning of parameter list (Signal from the MQL5.com Signal service) ============= Account type: Demo Publication date: 2020.07.02 16:29 Monitoring start date: 2020.07.02 16:29 Date of the latest update of the trading statistics: 2021.03.07 15:11 ID: 784584 Trading account leverage: 33 Trading result in pips: -19248988 Position in the Rating of Signals: 872 Number of subscribers: 6 Number of trades: 1825 Status of account subscription to a signal: No ------ Account balance: 12061.98 Account equity: 12590.32 Account growth in %: 1115.93 Maximum drawdown: 70.62 Signal subscription price: 0.00 Signal ROI (Return on Investment) in %: 1169.19 ------ Author login: "tradewai.com" Broker (company) name: "MetaQuotes Software Corp." Broker server: "MetaQuotes-Demo" Name: "Tradewai" Account currency: "USD" ============= End of parameter list (Signal from the MQL5.com Signal service) ============= Subscribed to signal ID 784584 "Tradewai"
その後、サブスクリプションパラメータが表示されます。
============= Signal copying parameters ============= Allow using signals for program: Yes Agree to the terms of use of the Signals service: Yes Enable copying deals by subscription: Yes Enable synchronization without confirmation dialog: No Copying Stop Loss and Take Profit: Yes Market order slippage when synchronizing positions and copying deals: Spread * 2.00 Percentage for converting deal volume: 50.00% Limit by deposit: 70% Limitation on signal equity: 7.00% Signal ID: 784584 Signal name: Tradewai
次のティックの間に、シグナルからのサブスクライブ解除の成功に関するメッセージを取得します。
Unsubscribed from the signal ID 784584 "Tradewai"
次の段階
次の記事では、銘柄チャートを操作するためのライブラリ機能の開発を開始します。
ライブラリの現在のバージョンのすべてのファイルは、テストおよびダウンロードできるように、MQL5のテストEAファイルと一緒に以下に添付されています。
ここに示されているテストEAでのシグナルの使用は、テスト目的のみを目的としています。
EAで提供されている例は、MQL5.comシグナルサービスを操作するためのライブラリとそのクラスに基づいてカスタムソリューションを実装するための一般的なアイデアのみを提供するものです。
質問や提案はコメント欄にお願いします。
*連載のこれまでの記事:
DoEasyライブラリでの価格(第62部): ティックシリーズをリアルタイムで更新して板情報で作業するための準備
DoEasyライブラリでの価格(第63部): 板情報とその抽象リクエストクラス
DoEasyライブラリでの価格(第64部): 板情報、DOMスナップショットのクラスおよびスナップショットシリーズオブジェクト
DoEasyライブラリでの価格(第65部): 板情報コレクションとMQL5.comシグナル操作クラス
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/9146
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索
新しい記事「DoEasyライブラリでのその他のクラス(第66部): MQL5.comシグナルコレクションクラス」はパブリッシュされました:
作者: Artyom Trishkin