
Прочие классы в библиотеке DoEasy (Часть 66): Класс-коллекция Сигналов MQL5.com
Содержание
- Концепция
- Доработка классов библиотеки
- Класс-коллекция объектов-mql5-сигналов
- Тестирование
- Что дальше
Концепция
В прошлой статье мы создали класс объекта-сигнала, представляющего собой один сигнал из множества, транслируемых в сервисе Сигналы MQL5.com.
Сегодня создадим класс-коллекцию сигналов, доступных в базе сигналов, и которые можно получить при помощи функции SignalBaseSelect(), указав индекс нужного нам сигнала.
Коллекция будет позволять хранить все имеющиеся в базе сигналы в удобном для поиска и сортировки списке. Мы сможем находить и возвращать списки сигналов по их различным свойствам, например, сможем получить списки только бесплатных, или наоборот — только платных сигналов, отсортировать их по одному из параметров, например, по прибыльности сигнала, либо сразу получить индекс сигнала в списке с параметром равным, больше, или меньше заданного значения. Зная заранее имя нужного нам сигнала, мы сможем быстро найти его в коллекции для дальнейшей с ним работы.
В классе-коллекции организуем возможность подписаться на выбранный в коллекции сигнал, либо отписаться от сигнала, на который уже осуществлена подписка на текущем аккаунте.
Помимо работы с объектами сервиса Сигналов MQL5.com доработаем класс объекта-снимка стакана цен — добавим в него дополнительные свойства, позволяющие сразу же при создании объекта-снимка стакана цен рассчитать по отдельности объёмы заявок на покупку и на продажу. Это избавит конечного пользователя от проведения дополнительных расчётов при работе со стаканом цен — мы сразу же будем знать совокупные объёмы каждого снимка стакана цен — как на покупку, так и на продажу, что позволит не прибегать к дополнительному поиску заявок Buy и Sell в стакане цен с последующим суммированием их объёмов при создании стратегий с использованием стакана цен и его объёмов.
Доработка классов библиотеки
Как уже сложилось, сразу же добавим все новые сообщения библиотеки в файл \MQL5\Include\DoEasy\Data.mqh.
Сначала впишем индексы новых сообщений:
//--- CMarketBookSnapshot MSG_MBOOK_SNAP_TEXT_SNAPSHOT, // Снимок стакана цен MSG_MBOOK_SNAP_VOLUME_BUY, // Объём на покупку MSG_MBOOK_SNAP_VOLUME_SELL, // Объём на продажу //--- CMBookSeries MSG_MBOOK_SERIES_TEXT_MBOOKSERIES, // Серия снимков стакана цен MSG_MBOOK_SERIES_ERR_ADD_TO_LIST, // Ошибка. Не удалось добавить серию снимков стакана цен в список
...
//--- CMQLSignal MSG_SIGNAL_MQL5_TEXT_SIGNAL, // Сигнал MSG_SIGNAL_MQL5_TEXT_SIGNAL_MQL5, // Сигнал сервиса сигналов mql5.com MSG_SIGNAL_MQL5_TRADE_MODE, // Тип счета MSG_SIGNAL_MQL5_DATE_PUBLISHED, // Дата публикации MSG_SIGNAL_MQL5_DATE_STARTED, // Дата начала мониторинга MSG_SIGNAL_MQL5_DATE_UPDATED, // Дата последнего обновления торговой статистики MSG_SIGNAL_MQL5_ID, // ID MSG_SIGNAL_MQL5_LEVERAGE, // Плечо торгового счета MSG_SIGNAL_MQL5_PIPS, // Результат торговли в пипсах MSG_SIGNAL_MQL5_RATING, // Позиция в рейтинге сигналов MSG_SIGNAL_MQL5_SUBSCRIBERS, // Количество подписчиков MSG_SIGNAL_MQL5_TRADES, // Количество трейдов MSG_SIGNAL_MQL5_SUBSCRIPTION_STATUS, // Состояние подписки счёта на этот сигнал MSG_SIGNAL_MQL5_EQUITY, // Средства на счете MSG_SIGNAL_MQL5_GAIN, // Прирост счета в процентах MSG_SIGNAL_MQL5_MAX_DRAWDOWN, // Максимальная просадка MSG_SIGNAL_MQL5_PRICE, // Цена подписки на сигнал MSG_SIGNAL_MQL5_ROI, // Значение ROI (Return on Investment) сигнала в % MSG_SIGNAL_MQL5_AUTHOR_LOGIN, // Логин автора MSG_SIGNAL_MQL5_BROKER, // Наименование брокера (компании) MSG_SIGNAL_MQL5_BROKER_SERVER, // Сервер брокера MSG_SIGNAL_MQL5_NAME, // Имя MSG_SIGNAL_MQL5_CURRENCY, // Валюта счета MSG_SIGNAL_MQL5_TEXT_GAIN, // Прирост MSG_SIGNAL_MQL5_TEXT_DRAWDOWN, // Просадка MSG_SIGNAL_MQL5_TEXT_SUBSCRIBERS, // Подписчиков //--- CMQLSignalsCollection MSG_MQLSIG_COLLECTION_TEXT_MQL5_SIGNAL_COLLECTION, // Коллекция сигналов сервиса сигналов mql5.com MSG_MQLSIG_COLLECTION_TEXT_SIGNALS_PAID, // Платных сигналов MSG_MQLSIG_COLLECTION_TEXT_SIGNALS_FREE, // Бесплатных сигналов MSG_MQLSIG_COLLECTION_TEXT_SIGNALS_NEW, // Новый сигнал добавлен в коллекцию MSG_MQLSIG_COLLECTION_ERR_FAILED_GET_SIGNAL, // Не удалось получить сигнал из коллекции MSG_SIGNAL_INFO_PARAMETERS, // Параметры копирования сигнала MSG_SIGNAL_INFO_EQUITY_LIMIT, // Процент для конвертации объема сделки MSG_SIGNAL_INFO_SLIPPAGE, // Проскальзывание, с которым выставляются рыночные ордера при синхронизации позиций и копировании сделок MSG_SIGNAL_INFO_VOLUME_PERCENT, // Ограничение по средствам для сигнала MSG_SIGNAL_INFO_CONFIRMATIONS_DISABLED, // Разрешение синхронизации без показа диалога подтверждения MSG_SIGNAL_INFO_COPY_SLTP, // Копирование Stop Loss и Take Profit MSG_SIGNAL_INFO_DEPOSIT_PERCENT, // Ограничение по депозиту MSG_SIGNAL_INFO_ID, // Идентификатор сигнала MSG_SIGNAL_INFO_SUBSCRIPTION_ENABLED, // Разрешение на копирование сделок по подписке MSG_SIGNAL_INFO_TERMS_AGREE, // Согласие с условиями использования сервиса "Сигналы" MSG_SIGNAL_INFO_NAME, // Имя сигнала MSG_SIGNAL_INFO_SIGNALS_PERMISSION, // Разрешение на работу с сигналами для программы MSG_SIGNAL_INFO_TEXT_SIGNAL_SUBSCRIBED, // Осуществлена подписка на сигнал MSG_SIGNAL_INFO_TEXT_SIGNAL_UNSUBSCRIBED, // Осуществлена отписка от сигнала MSG_SIGNAL_INFO_ERR_SIGNAL_NOT_ALLOWED, // Работа с сервисом сигналов для программы не разрешена MSG_SIGNAL_INFO_TEXT_CHECK_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(), позволяющие выводить сообщения с указанием его исходной функции или метода и без такого указания.
Откроем файл \MQL5\Include\DoEasy\Services\Message.mqh и допишем в него объявление перегруженного метода:
//--- (1,2) выводит сообщение в журнал по идентификатору, (3) на e-mail, (4) на мобильное устройство 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) отправляет файл на FTP, (2) возвращает код ошибки static bool ToFTP(const string filename,const string ftp_path=NULL); static int GetError(void) { return CMessage::m_global_error; }
За пределами тела класса напишем его реализацию:
//+------------------------------------------------------------------+ //| Выводит сообщение в журнал по идентификатору сообщения | //+------------------------------------------------------------------+ 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))); } //+------------------------------------------------------------------+ //| Выводит сообщение в журнал по идентификатору сообщения | //+------------------------------------------------------------------+ 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))); } //+------------------------------------------------------------------+
Как видим, в отличии от первой формы вызова метода во второй его форме добавлен ещё один входной параметр, в котором и будет передаваться наименование метода или функции, из которых был вызван метод ToLog(), и которое будет выводиться в журнал перед сообщением.
К данному классу мы ещё вернёмся в последующих статьях для внесения в него доработок при переводе всех классов библиотеки на вывод сообщений посредством этого класса.
Доработаем класс CMBookSnapshot в файле \MQL5\Include\DoEasy\Objects\Book\MarketBookSnapshot.mqh.
В приватной секции класса впишем переменные-члены класса для хранения совокупных объёмов снимка стакана цен на покупку и продажу:
//+------------------------------------------------------------------+ //| Класс "Снимок стакана цен" | //+------------------------------------------------------------------+ class CMBookSnapshot : public CBaseObj { private: string m_symbol; // Символ long m_time; // Время снимка int m_digits; // Digits символа long m_volume_buy; // Объём стакана на покупку long m_volume_sell; // Объём стакана на продажу double m_volume_buy_real; // Объём стакана на покупку с повышенной точностью double m_volume_sell_real; // Объём стакана на продажу с повышенной точностью CArrayObj m_list; // Список объектов-заявок стакана цен public:
В разделе методов упрощённого доступа к свойствам объекта-снимка стакана цен публичной секции класса впишем методы, возвращающие эти вновь добавленные свойства класса, и методы для вывода их описания:
//+------------------------------------------------------------------+ //|Методы упрощённого доступа к свойствам объекта-снимка стакана цен | //+------------------------------------------------------------------+ //--- Устанавливает (1) символ, (2) время снимка стакана цен, (3) указанное время всем заявкам в стакане 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); //--- Возвращает (1) символ стакана цен, (2) Digits символа, (3) время снимка //--- объём снимка стакана цен (4) на покупку, (5) на продажу, //--- с повышенной точностью (6) на покупку, (7) на продажу, 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; } //--- Возвращает описание объёма стакана (1) на покупку, (2) на продажу string VolumeBuyDescription(void); string VolumeSellDescription(void); }; //+------------------------------------------------------------------+
При создании нового объекта-снимка стакана цен мы просматриваем в цикле все его заявки, создаём объекты этих заявок и складываем их в список. Сейчас нам нужно в конструкторе класса учитывать типы заявок и сразу же прибавлять к значению переменных, хранящих совокупный объём заявок на покупку и продажу, объём текущей заявки в зависимости от её типа. Таким образом, каждая переменная в итоге будет хранить общий объём заявок либо на покупку, либо на продажу сразу же при создании объекта-снимка стакана цен.
Впишем эти доработки в параметрический конструктор класса:
//+------------------------------------------------------------------+ //| Параметрический конструктор | //+------------------------------------------------------------------+ CMBookSnapshot::CMBookSnapshot(const string symbol,const long time,MqlBookInfo &book_array[]) : m_time(time) { //--- Устанавливаем символ this.SetSymbol(symbol); //--- Очищаем список this.m_list.Clear(); //--- В цикле по массиву структур 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++) { //--- Создаём объекты-заявки текущего снимка стакана цен в зависимости от типа заявки 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; //--- Устанавливаем заявке время снимка стакана цен mbook_ord.SetTime(this.m_time); //--- Ставим списку флаг сортированного списка (по значению цены) и добавляем в него текущий объект-заявку //--- Если не удалось добавить объект в список заявок стакана цен - удаляем объект-заявку this.m_list.Sort(SORT_BY_MBOOK_ORD_PRICE); if(!this.m_list.InsertSort(mbook_ord)) delete mbook_ord; //--- Если объект-заявка успешно добавлен в список заявок снимка стакана - дополняем общие объёмы снимка 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; } } } } //+------------------------------------------------------------------+
Здесь: в первую очередь инициализируем переменные, хранящие общие объёмы всех заявок снимка стакана цен на покупку и продажу. Затем — уже в теле цикла по всем заявкам стакана, в зависимости от типа заявки, добавляем к переменным, хранящим общие объёмы, и соответствующие типу заявки, объём текущей заявки. Таким образом, у нас по окончании цикла по всем заявкам снимка стакана цен во всех переменных будут храниться совокупные объёмы на покупку и на продажу.
В методы, выводящие в журнал краткое описание объекта и все свойства объекта, добавим вывод общих объёмов на покупку и продажу:
//+------------------------------------------------------------------+ //| Выводит в журнал краткое описание объекта | //+------------------------------------------------------------------+ 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),")"); } //+------------------------------------------------------------------+ //| Выводит в журнал свойства объекта | //+------------------------------------------------------------------+ 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()); } } //+------------------------------------------------------------------+
За пределами тела класса напишем реализацию двух новых методов, возвращающих описания объёмов стакана на покупку и на продажу:
//+------------------------------------------------------------------+ //| Возвращает описание объёма стакана на покупку | //+------------------------------------------------------------------+ string CMBookSnapshot::VolumeBuyDescription(void) { return(CMessage::Text(MSG_MBOOK_SNAP_VOLUME_BUY)+": "+(this.VolumeBuyReal()>0 ? ::DoubleToString(this.VolumeBuyReal(),2) : (string)this.VolumeBuy())); } //+------------------------------------------------------------------+ //| Возвращает описание объёма стакана на продажу | //+------------------------------------------------------------------+ string CMBookSnapshot::VolumeSellDescription(void) { return(CMessage::Text(MSG_MBOOK_SNAP_VOLUME_SELL)+": "+(this.VolumeSellReal()>0 ? ::DoubleToString(this.VolumeSellReal(),2) : (string)this.VolumeSell())); } //+------------------------------------------------------------------+
В обоих методах проверяется значение объёма с повышенной точностью и, если значение больше нуля, то возвращается заголовок + это значение объёма (вещественное), иначе — целочисленное значение.
В класс-коллекцию серий снимков стаканов цен CMBookSeriesCollection в файле \MQL5\Include\DoEasy\Collections\BookSeriesCollection.mqh,
в его публичную секцию добавим методы, возвращающие списки по указанным критериям свойств объектов списка:
public: //--- Возвращает (1) себя, (2) список-коллекцию серий стаканов цен CMBookSeriesCollection *GetObject(void) { return &this; } CArrayObj *GetList(void) { return &this.m_list; } //--- Возвращает список по выбранному (1) целочисленному, (2) вещественному и (3) строковому свойству, удовлетворяющему сравниваемому критерию 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); } //--- Возвращает количество серий стаканов цен в списке int DataTotal(void) const { return this.m_list.Total(); } //--- Возвращает указатель на объект серий стаканов цен (1) по символу, (2) по индексу в списке
В классе объекта-заявки стакана цен CMQLSignal в файле \MQL5\Include\DoEasy\Objects\MQLSignalBase\MQLSignal.mqh дополним метод PrintShort() входным значением-флагом, указывающим на необходимость вывода дефиса перед описанием объекта:
//--- Выводит в журнал описание свойств объекта (full_prop=true - все свойства, false - только поддерживаемые) void Print(const bool full_prop=false); //--- Выводит в журнал краткое описание объекта virtual void PrintShort(const bool dash=false); //--- Возвращает краткое наименование объекта virtual string Header(const bool shrt=false);
И внесём правки в тело метода:
//+------------------------------------------------------------------+ //| Выводит в журнал краткое описание объекта | //+------------------------------------------------------------------+ 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() ); } //+------------------------------------------------------------------+
Здесь: в зависимости от переданного значения перед описанием объекта выводится дефис либо не выводится, и в самом конце описания добавлено значение о количестве подписчиков на сигнал.
В самом конце тела класса впишем новый метод, осуществляющий подписку на сигнал, описываемый данным объектом:
//--- Возвращает наименование типа счёта string TradeModeDescription(void); //--- Осуществляет подписку на сигнал bool Subscribe(void) { return ::SignalSubscribe(this.ID()); } }; //+------------------------------------------------------------------+
В конструкторе класса поправим инициализацию переменной, хранящей статус подписки на сигнал:
//+------------------------------------------------------------------+ //| Параметрический конструктор | //+------------------------------------------------------------------+ 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. Теперь же мы будем её инициализировать результатом сравнения идентификатора объекта-сигнала с идентификатором текущего подписанного сигнала. Если на какой-либо сигнал есть подписка, то этот сигнал будет "текущим подписанным", и он будет иметь идентификатор сигнала из базы Сигналов MQL5.com, которые мы и сравниваем. Если они равны, то значит на этот сигнал оформлена подписка — результат сравнения будет равен true, иначе — false.
Так как сегодня создаём новую коллекцию, то нам необходимо определить для неё свой идентификатор. В файле \MQL5\Include\DoEasy\Defines.mqh впишем идентификатор коллекции сигналов сервиса Сигналы MQL5.com:
//--- Идентификаторы списков коллекций #define COLLECTION_HISTORY_ID (0x777A) // Идентификатор списка исторической коллекции #define COLLECTION_MARKET_ID (0x777B) // Идентификатор списка рыночной коллекции #define COLLECTION_EVENTS_ID (0x777C) // Идентификатор списка коллекции событий #define COLLECTION_ACCOUNT_ID (0x777D) // Идентификатор списка коллекции аккаунтов #define COLLECTION_SYMBOLS_ID (0x777E) // Идентификатор списка коллекции символов #define COLLECTION_SERIES_ID (0x777F) // Идентификатор списка коллекции таймсерий #define COLLECTION_BUFFERS_ID (0x7780) // Идентификатор списка коллекции индикаторных буферов #define COLLECTION_INDICATORS_ID (0x7781) // Идентификатор списка коллекции индикаторов #define COLLECTION_INDICATORS_DATA_ID (0x7782) // Идентификатор списка коллекции индикаторных данных #define COLLECTION_TICKSERIES_ID (0x7783) // Идентификатор списка коллекции тиковых серий #define COLLECTION_MBOOKSERIES_ID (0x7784) // Идентификатор списка коллекции серий стаканов цен #define COLLECTION_MQL5_SIGNALS_ID (0x7785) // Идентификатор списка коллекции mql5-сигналов //--- Параметры данных для файловых операций
Для полноценной работы с коллекцией сигналов сервиса Сигналы MQL5.com нам нужно создать методы для поиска и сортировки по свойствам объектов-сигналов. Для каждой коллекции мы создаём свои методы поиска и сортировки. Все они идентичны друг другу и описывались нами подробно в третьей статье описания библиотеки.
В файле класса CSelect для поиска и сортировки, находящегося в расположении \MQL5\Include\DoEasy\Services\Select.mqh,
подключим файл класса объекта-mql5-сигнала и объявим новые методы для работы с коллекцией объектов-сигналов:
//+------------------------------------------------------------------+ //| Включаемые файлы | //+------------------------------------------------------------------+ #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" //+------------------------------------------------------------------+
//+------------------------------------------------------------------+ //| Методы работы с данными mql5-сигналов | //+------------------------------------------------------------------+ //--- Возвращает список mql5-сигналов, где одно из (1) целочисленных, (2) вещественных и (3) строковых свойств удовлетворяет заданному критерию 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); //--- Возвращает индекс mql5-сигнала в списке с максимальным значением (1) целочисленного, (2) вещественного и (3) строкового свойства 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); //--- Возвращает индекс mql5-сигнала в списке с минимальным значением (1) целочисленного, (2) вещественного и (3) строкового свойства 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); //--- }; //+------------------------------------------------------------------+
За пределами тела класса напишем их реализацию:
//+------------------------------------------------------------------+ //| Методы работы с данными mql5-сигналов | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Возвращает список mql5-сигналов, где одно из целочисленных | //| свойств удовлетворяет заданному критерию | //+------------------------------------------------------------------+ 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; } //+------------------------------------------------------------------+ //| Возвращает список mql5-сигналов, где одно из вещественных | //| свойств удовлетворяет заданному критерию | //+------------------------------------------------------------------+ 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; } //+------------------------------------------------------------------+ //| Возвращает список mql5-сигналов, где одно из строковых | //| свойств удовлетворяет заданному критерию | //+------------------------------------------------------------------+ 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; } //+------------------------------------------------------------------+ //| Возвращает индекс mql5-сигнала в списке | //| с максимальным значением целочисленного свойства | //+------------------------------------------------------------------+ 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; } //+------------------------------------------------------------------+ //| Возвращает индекс mql5-сигнала в списке | //| с максимальным значением вещественного свойства | //+------------------------------------------------------------------+ 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; } //+------------------------------------------------------------------+ //| Возвращает индекс mql5-сигнала в списке | //| с максимальным значением строкового свойства | //+------------------------------------------------------------------+ 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; } //+------------------------------------------------------------------+ //| Возвращает индекс mql5-сигнала в списке | //| с минимальным значением целочисленного свойства | //+------------------------------------------------------------------+ 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; } //+------------------------------------------------------------------+ //| Возвращает индекс mql5-сигнала в списке | //| с минимальным значением вещественного свойства | //+------------------------------------------------------------------+ 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; } //+------------------------------------------------------------------+ //| Возвращает индекс mql5-сигнала в списке | //| с минимальным значением строкового свойства | //+------------------------------------------------------------------+ 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\ создадим новый класс CMQLSignalsCollection в файле MQLSignalsCollection.mqh.
К файлу класса подключим все файлы классов, необходимых для его работы:
//+------------------------------------------------------------------+ //| MQLSignalsCollection.mqh | //| Copyright 2021, MetaQuotes Software Corp. | //| https://mql5.com/ru/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Software Corp." #property link "https://mql5.com/ru/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Включаемые файлы | //+------------------------------------------------------------------+ #include "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\MQLSignalBase\MQLSignal.mqh" //+------------------------------------------------------------------+
Класс должен быть унаследован от базового объекта всех объектов библиотеки:
//+------------------------------------------------------------------+ //| Коллекция объектов-mql5-сигналов | //+------------------------------------------------------------------+ class CMQLSignalsCollection : public CBaseObj { }
Рассмотрим тело класса целиком, а затем разберём составляющие его методы:
//+------------------------------------------------------------------+ //| MQLSignalsCollection.mqh | //| Copyright 2021, MetaQuotes Software Corp. | //| https://mql5.com/ru/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2021, MetaQuotes Software Corp." #property link "https://mql5.com/ru/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Включаемые файлы | //+------------------------------------------------------------------+ #include "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\MQLSignalBase\MQLSignal.mqh" //+------------------------------------------------------------------+ //| Коллекция объектов-mql5-сигналов | //+------------------------------------------------------------------+ class CMQLSignalsCollection : public CBaseObj { private: CListObj m_list; // Список объектов-mql5-сигналов int m_signals_base_total; // Количество сигналов в базе сигналов mql5 //--- Осуществляет подписку на сигнал bool Subscribe(const long signal_id); //--- Устанавливает флаг разрешения синхронизации без показа диалога подтверждения bool CurrentSetConfirmationsDisableFlag(const bool flag); //--- Устанавливает флаг копирования Stop Loss и Take Profit bool CurrentSetSLTPCopyFlag(const bool flag); //--- Устанавливает флаг разрешения на копирование сделок по подписке bool CurrentSetSubscriptionEnabledFlag(const bool flag); public: //--- Возвращает (1) себя, (2) список-коллекцию серий стаканов цен CMQLSignalsCollection *GetObject(void) { return &this; } CArrayObj *GetList(void) { return &this.m_list; } //--- Возвращает список по выбранному (1) целочисленному, (2) вещественному и (3) строковому свойству, удовлетворяющему сравниваемому критерию 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); } //--- Возвращает количество объектов-mql5-сигналов в списке int DataTotal(void) const { return this.m_list.Total(); } //--- Возвращает указатель на объект-mql5-сигнал (1) по идентификатору, (2) по имени, (3) по индексу в списке CMQLSignal *GetMQLSignal(const long id); CMQLSignal *GetMQLSignal(const string name); CMQLSignal *GetMQLSignal(const int index) { return this.m_list.At(index); } //--- Создаёт список-коллекцию объектов-mql5-сигналов bool CreateCollection(void); //--- Обновляет список-коллекцию объектов-mql5-сигналов void Refresh(const bool messages=true); //--- Выводит в журнал (1) полное, (2) краткое описание коллекции void Print(void); void PrintShort(const bool list=false,const bool paid=true,const bool free=true); //--- Конструктор CMQLSignalsCollection(); //--- Осуществляет подписку на сигнал по (1) идентификатору, (2) имени сигнала bool SubscribeByID(const long signal_id); bool SubscribeByName(const string signal_name); //+------------------------------------------------------------------+ //| Методы работы с текущим сигналом, на который оформлена подписка | //+------------------------------------------------------------------+ //--- Возвращает флаг разрешения работы с сервисом сигналов bool ProgramIsAllowed(void) { return (bool)::MQLInfoInteger(MQL_SIGNALS_ALLOWED); } //--- Осуществляет отписку от текущего подписанного сигнала bool CurrentUnsubscribe(void); //--- Устанавливает процент для конвертации объема сделки bool CurrentSetEquityLimit(const double value); //--- Устанавливает величину проскальзывания, с которой выставляются рыночные ордера при синхронизации позиций и копировании сделок bool CurrentSetSlippage(const double value); //--- Устанавливает ограничения по депозиту (в %) bool CurrentSetDepositPercent(const int value); //--- Возвращает процент для конвертации объема сделки double CurrentEquityLimit(void) { return ::SignalInfoGetDouble(SIGNAL_INFO_EQUITY_LIMIT); } //--- Возвращает величину проскальзывания, с которой выставляются рыночные ордера при синхронизации позиций и копировании сделок double CurrentSlippage(void) { return ::SignalInfoGetDouble(SIGNAL_INFO_SLIPPAGE); } //--- Возвращает флаг разрешения синхронизации без показа диалога подтверждения bool CurrentConfirmationsDisableFlag(void) { return (bool)::SignalInfoGetInteger(SIGNAL_INFO_CONFIRMATIONS_DISABLED); } //--- Возвращает флаг копирования Stop Loss и Take Profit bool CurrentSLTPCopyFlag(void) { return (bool)::SignalInfoGetInteger(SIGNAL_INFO_COPY_SLTP); } //--- Возвращает ограничения по депозиту (в %) int CurrentDepositPercent(void) { return (int)::SignalInfoGetInteger(SIGNAL_INFO_DEPOSIT_PERCENT); } //--- Возвращает флаг разрешения на копирование сделок по подписке bool CurrentSubscriptionEnabledFlag(void) { return (bool)::SignalInfoGetInteger(SIGNAL_INFO_SUBSCRIPTION_ENABLED); } //--- Возвращает значение ограничения по средствам для сигнала double CurrentVolumePercent(void) { return ::SignalInfoGetDouble(SIGNAL_INFO_VOLUME_PERCENT); } //--- Возвращает id сигнала long CurrentID(void) { return ::SignalInfoGetInteger(SIGNAL_INFO_ID); } //--- Возвращает флаг согласия с условиями использования сервиса "Сигналы" bool CurrentTermsAgreeFlag(void) { return (bool)::SignalInfoGetInteger(SIGNAL_INFO_TERMS_AGREE); } //--- Возвращает имя сигнала string CurrentName(void) { return ::SignalInfoGetString(SIGNAL_INFO_NAME); } //--- Устанавливает разрешение синхронизации без показа диалога подтверждения bool CurrentSetConfirmationsDisableON(void) { return this.CurrentSetConfirmationsDisableFlag(true); } //--- Устанавливает запрет синхронизации без показа диалога подтверждения bool CurrentSetConfirmationsDisableOFF(void){ return this.CurrentSetConfirmationsDisableFlag(false); } //--- Устанавливает разрешение копирования Stop Loss и Take Profit bool CurrentSetSLTPCopyON(void) { return this.CurrentSetSLTPCopyFlag(true); } //--- Устанавливает запрет копирования Stop Loss и Take Profit bool CurrentSetSLTPCopyOFF(void) { return this.CurrentSetSLTPCopyFlag(false); } //--- Устанавливает разрешение на копирование сделок по подписке bool CurrentSetSubscriptionEnableON(void) { return this.CurrentSetSubscriptionEnabledFlag(true); } //--- Устанавливает запрет на копирование сделок по подписке bool CurrentSetSubscriptionEnableOFF(void) { return this.CurrentSetSubscriptionEnabledFlag(false); } //--- Возвращает описание разрешения работы с сигналами для данной запущенной программы string ProgramIsAllowedDescription(void); //--- Возвращает описание процента для конвертации объема сделки string CurrentEquityLimitDescription(void); //--- Возвращает описание проскальзывания, с которой выставляются рыночные ордера при синхронизации позиций и копировании сделок string CurrentSlippageDescription(void); //--- Возвращает описание значения ограничения по средствам для сигнала string CurrentVolumePercentDescription(void); //--- Возвращает описание флага разрешения синхронизации без показа диалога подтверждения string CurrentConfirmationsDisableFlagDescription(void); //--- Возвращает описание флага копирования Stop Loss и Take Profit string CurrentSLTPCopyFlagDescription(void); //--- Возвращает описание ограничения по депозиту (в %) string CurrentDepositPercentDescription(void); //--- Возвращает описание флага разрешения на копирование сделок по подписке string CurrentSubscriptionEnabledFlagDescription(void); //--- Возвращает описание id сигнала string CurrentIDDescription(void); //--- Возвращает описание флага согласия с условиями использования сервиса "Сигналы" string CurrentTermsAgreeFlagDescription(void); //--- Возвращает описание имени сигнала string CurrentNameDescription(void); //--- Выводит в журнал параметры настроек копирования сигналов void CurrentSubscriptionParameters(void); //--- }; //+------------------------------------------------------------------+
В приватной секции класса расположен объект списка, в котором будем хранить объекты-mql5-сигналы, и вспомогательные переменные и методы.
В публичной секции класса расположены стандартные для всех объектов библиотеки методы работы со списком-коллекцией объектов и два метода для подписки на выбранный сигнал по его идентификатору и имени. Также в публичной секции класса расположены методы для работы с текущим сигналом, на который оформлена подписка.
Разберём реализацию некоторых методов.
В конструкторе класса очищаем список-коллекцию, устанавливаем для него флаг сортированного списка, устанавливаем списку идентификатор коллекции объектов-mql5-сигналов, записываем общее количество сигналов в базе Сигналов MQL5.com и вызываем метод создания коллекции.
//+------------------------------------------------------------------+ //| Конструктор | //+------------------------------------------------------------------+ 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(); } //+------------------------------------------------------------------+
Так как список сигналов мы не будем автоматически обновлять и контролировать средствами библиотеки, то нам в принципе достаточно создать только метод обновления списка, в котором будут считываться все имеющиеся в базе сигналы и записываться в список-коллекцию. Пользователю самому необходимо будет вызывать метод обновления Refresh() перед получением каких-либо данных из коллекции и при желании иметь свежий список сигналов из базы Сигналов MQL5.com. Но метод создания коллекции у нас тоже будет — лишь в качестве совместимости с набором типичных методов коллекций библиотеки. В самом же методе просто будет очищаться список и вызываться метод обновления коллекции. После первого вызова метода Refresh() из метода создания коллекции список-коллекция будет заполнен, и далее можно уже работать с этим списком. При необходимости обновить список-коллекцию в поисках возможных новых сигналов нужно просто вызвать метод Refresh() перед обращением к списку-коллекции.
Метод создания коллекции:
//+------------------------------------------------------------------+ //| Создаёт список-коллекцию объектов-mql5-сигналов | //+------------------------------------------------------------------+ 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.
Метод обновления списка-коллекции:
//+------------------------------------------------------------------+ //| Обновляет список-коллекцию объектов-mql5-сигналов | //+------------------------------------------------------------------+ void CMQLSignalsCollection::Refresh(const bool messages=true) { this.m_signals_base_total=::SignalBaseTotal(); //--- цикл по всем сигналам в базе сигналов for(int i=0;i<this.m_signals_base_total;i++) { //--- Выбираем сигнал из базы сигналов по индексу цикла if(!::SignalBaseSelect(i)) continue; //--- Получаем идентификатор текущего сигнала и //--- на его основании создаём новый объект-mql5-сигнал long id=::SignalBaseGetInteger(SIGNAL_BASE_ID); CMQLSignal *signal=new CMQLSignal(id); if(signal==NULL) continue; //--- Устанавливаем списку флаг сортировки по идентификатору сигналов и, //--- если такой сигнал уже есть в списке-коллекции - //--- удаляем созданный объект и идём на следующую итерацию цикла m_list.Sort(SORT_BY_SIGNAL_MQL5_ID); if(this.m_list.Search(signal)!=WRONG_VALUE) { delete signal; continue; } //--- Если новый объект-сигнал не удалось добавить в список-коллекцию - //--- удаляем созданный объект и идём на следующую итерацию цикла if(!this.m_list.InsertSort(signal)) { delete signal; continue; } //--- Если объект-mql5-сигнал успешно добавлен в коллекцию //--- и установлен флаг сообщения о новом объекте в переданных в метод параметрах - //--- выводим сообщение о новом найденном сигнале else if(messages) { ::Print(DFUN,CMessage::Text(MSG_MQLSIG_COLLECTION_TEXT_SIGNALS_NEW),":"); signal.PrintShort(true); } } } //+------------------------------------------------------------------+
Логика метода подробно описана в комментариях к коду. Вкратце: в метод передаётся флаг необходимости сообщить о новом найденном сигнале. Так как метод не очищает список-коллекцию, то только новый найденный сигнал может быть добавлен в него. Если флаг сообщения установлен, то при успешном добавлении нового объекта-сигнала в список, в журнал будет выведено сообщение о новом найденном сигнале.
На данный момент это простейший метод, в котором не реализовано обновление параметров существующих сигналов — их можно будет обновить самостоятельно в своих программах с помощью доступа к объекту-сигналу по его идентификатору и установке новых значений в его свойства. Позже мы добавим автоматическое обновление параметров существующих сигналов по времени и, если класс-коллекция Сигналов MQL5.com будет востребован, то мы создадим для него отправку событий о новых сигналах и об изменении параметров отслеживаемых сигналов.
Метод, возвращающий указатель на объект-mql5-сигнал по идентификатору сигнала:
//+------------------------------------------------------------------+ //| Возвращает указатель на объект-mql5-сигнал по идентификатору | //+------------------------------------------------------------------+ CMQLSignal *CMQLSignalsCollection::GetMQLSignal(const long id) { CArrayObj *list=GetList(SIGNAL_MQL5_PROP_ID,id,EQUAL); return(list!=NULL ? list.At(0) : NULL); } //+------------------------------------------------------------------+
Получаем список объектов-mql5-сигналов по идентификатору сигнала и возвращаем либо единственный объект из полученного списка, либо NULL.
Метод, возвращающий указатель на объект-mql5-сигнал по имени сигнала:
//+------------------------------------------------------------------+ //| Возвращает указатель на объект-mql5-сигнал по имени | //+------------------------------------------------------------------+ CMQLSignal *CMQLSignalsCollection::GetMQLSignal(const string name) { CArrayObj *list=GetList(SIGNAL_MQL5_PROP_NAME,name,EQUAL); return(list!=NULL ? list.At(0) : NULL); } //+------------------------------------------------------------------+
Получаем список объектов-mql5-сигналов по имени сигнала и возвращаем либо единственный объект из полученного списка, либо NULL.
Метод, выводящий в журнал полное описание коллекции:
//+------------------------------------------------------------------+ //| Выводит в журнал полное описание коллекции | //+------------------------------------------------------------------+ 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(); } } //+------------------------------------------------------------------+
Сначала выводится заголовок, а затем, в цикле по списку-коллекции получаем очередной объект-mql5-сигнал и выводим его полное описание.
Метод, выводящий в журнал краткое описание коллекции:
//+------------------------------------------------------------------+ //| Выводит в журнал краткое описание коллекции | //+------------------------------------------------------------------+ void CMQLSignalsCollection::PrintShort(const bool list=false,const bool paid=true,const bool free=true) { //--- Выводим в журнал заголовок ::Print(CMessage::Text(MSG_MQLSIG_COLLECTION_TEXT_MQL5_SIGNAL_COLLECTION),":"); //--- Если полный список - выводим в журнал краткие описания всех сигналов в коллекции //--- в соответствии с флагами необходимости вывода платных и бесплатных сигналов 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); } //--- Если не список сигналов else { //--- Сортируем список по цене сигнала this.m_list.Sort(SORT_BY_SIGNAL_MQL5_PRICE); //--- Получаем список бесплатных сигналов и их количество CArrayObj *list_free=this.GetList(SIGNAL_MQL5_PROP_PRICE,0,EQUAL); int num_free=(list_free==NULL ? 0 : list_free.Total()); //--- Сортируем список по цене сигнала this.m_list.Sort(SORT_BY_SIGNAL_MQL5_PRICE); //--- Получаем список платных сигналов и их количество CArrayObj *list_paid=this.GetList(SIGNAL_MQL5_PROP_PRICE,0,MORE); int num_paid=(list_paid==NULL ? 0 : list_paid.Total()); //--- Распечатываем в журнал количество бесплатных и платных сигналов в коллекции ::Print ( "- ",CMessage::Text(MSG_MQLSIG_COLLECTION_TEXT_SIGNALS_FREE),": ",(string)num_free, ", ",CMessage::Text(MSG_MQLSIG_COLLECTION_TEXT_SIGNALS_PAID),": ",(string)num_paid ); } } //+------------------------------------------------------------------+
В этом методе, в зависимости от переданных флагов, распечатываются в журнал разные сообщения и списки.
Сначала выводится заголовок, затем, если установлен флаг списка, то в журнал распечатываются краткие описания сигналов в коллекции. При этом учитываются флаги платных и бесплатных сигналов. В зависимости от их состояния в журнал выводятся либо все сигналы, либо только платные, либо только бесплатные.
Если выводить нужно описание не списком, то после заголовка выводится общее количество бесплатных и платных сигналов в списке-коллекции.
Методы, осуществляющие подписку на сигнал (приватный метод) и отписку от существующего сигнала (публичный метод):
//+------------------------------------------------------------------+ //| Осуществляет подписку на сигнал | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::Subscribe(const long signal_id) { //--- Если для программы не установлено разрешение на работу с сигналами - //--- выводим об этом сообщение и рекомендацию проверить настройки программы 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; } //--- Если подписка на сигнал не удалась - выводим сообщение об ошибкеи возвращаем false ::ResetLastError(); if(!::SignalSubscribe(signal_id)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Подписка успешна. Выводим сообщение об успешной подписке на сигнал и возвращаем true ::Print(CMessage::Text(MSG_SIGNAL_INFO_TEXT_SIGNAL_SUBSCRIBED)," ID ",(string)this.CurrentID()," \"",CurrentName(),"\""); return true; } //+------------------------------------------------------------------+ //| Осуществляет отписку от подписанного сигнала | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::CurrentUnsubscribe(void) { //--- Если для программы не установлено разрешение на работу с сигналами - //--- выводим об этом сообщение и рекомендацию проверить настройки программы 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; } //--- Запоминаем идентификатор и имя текущего подписанного сигнала ::ResetLastError(); long id=this.CurrentID(); string name=this.CurrentName(); //--- Если идентификатор равен нулю (нет подписки) - возвращаем true if(id==0) return true; //--- Если отписаться от сигнала не удалось - выводим сообщение об ошибкеи возвращаем false if(!::SignalUnsubscribe()) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } //--- Успешно отписались от сигнала. Выводим сообщение об успешной отписке от сигнала и возвращаем true ::Print(CMessage::Text(MSG_SIGNAL_INFO_TEXT_SIGNAL_UNSUBSCRIBED)," ID ",(string)id," \"",name,"\""); return true; } //+------------------------------------------------------------------+
Логика работы методов подробно прокомментирована в листинге методов.
Публичный метод, осуществляющий подписку на сигнал по идентификатору сигнала:
//+------------------------------------------------------------------+ //| Осуществляет подписку на сигнал по идентификатору | //+------------------------------------------------------------------+ 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()); } //+------------------------------------------------------------------+
Здесь: получаем указатель на объект-mql5-сигнал в списке-коллекции по переданному в метод идентификатору и возвращаем результат работы приватного метода подписки на сигнал, рассмотренному нами выше.
Публичный метод, осуществляющий подписку на сигнал по имени сигнала:
//+------------------------------------------------------------------+ //| Осуществляет подписку на сигнал по имени сигнала | //+------------------------------------------------------------------+ 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-сигнал в списке-коллекции по переданному в метод имени сигнала (имя должно быть заранее известно) и возвращаем результат работы приватного метода подписки на сигнал, рассмотренному нами выше.
Методы установки значений копирования торговых сигналов:
//+------------------------------------------------------------------+ //| Устанавливает процент для конвертации объема сделки | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::CurrentSetEquityLimit(const double value) { ::ResetLastError(); if(!::SignalInfoSetDouble(SIGNAL_INFO_EQUITY_LIMIT,value)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } return true; } //+------------------------------------------------------------------+ //| Устанавливает величину проскальзывания, с которой выставляются | //| рыночные ордера при синхронизации позиций и копировании сделок | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::CurrentSetSlippage(const double value) { ::ResetLastError(); if(!::SignalInfoSetDouble(SIGNAL_INFO_SLIPPAGE,value)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } return true; } //+------------------------------------------------------------------+ //| Устанавливает флаг разрешения синхронизации | //| без показа диалога подтверждения | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::CurrentSetConfirmationsDisableFlag(const bool flag) { ::ResetLastError(); if(!::SignalInfoSetInteger(SIGNAL_INFO_CONFIRMATIONS_DISABLED,flag)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } return true; } //+------------------------------------------------------------------+ //| Устанавливает флаг копирования Stop Loss и 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; } //+------------------------------------------------------------------+ //| Устанавливает ограничения по депозиту (в %) | //+------------------------------------------------------------------+ bool CMQLSignalsCollection::CurrentSetDepositPercent(const int value) { ::ResetLastError(); if(!::SignalInfoSetInteger(SIGNAL_INFO_DEPOSIT_PERCENT,value)) { CMessage::ToLog(DFUN,::GetLastError(),true); return false; } return true; } //+------------------------------------------------------------------+ //| Устанавливает флаг разрешения на копирование сделок по подписке | //+------------------------------------------------------------------+ 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.
Методы, возвращающие описания параметров настройки копирования торговых сигналов:
//+------------------------------------------------------------------+ //| Возвращает описание разрешения работы с сигналами | //| для данной запущенной программы | //+------------------------------------------------------------------+ 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)) ); } //+------------------------------------------------------------------+ //| Возвращает описание процента для конвертации объема сделки | //+------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentEquityLimitDescription(void) { return CMessage::Text(MSG_SIGNAL_INFO_EQUITY_LIMIT)+": "+::DoubleToString(this.CurrentEquityLimit(),2)+"%"; } //+------------------------------------------------------------------+ //| Возвращает описание проскальзывания, с которой выставляются | //| рыночные ордера при синхронизации позиций и копировании сделок | //+------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentSlippageDescription(void) { return CMessage::Text(MSG_SIGNAL_INFO_SLIPPAGE)+": "+CMessage::Text(MSG_LIB_TEXT_BAR_SPREAD)+" * "+::DoubleToString(this.CurrentSlippage(),2); } //+------------------------------------------------------------------+ //| Возвращает описание значения ограничения по средствам для сигнала| //+------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentVolumePercentDescription(void) { return CMessage::Text(MSG_SIGNAL_INFO_VOLUME_PERCENT)+": "+::DoubleToString(this.CurrentVolumePercent(),2)+"%"; } //+------------------------------------------------------------------+ //| Возвращает описание флага разрешения синхронизации | //| без показа диалога подтверждения | //+------------------------------------------------------------------+ 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)) ); } //+------------------------------------------------------------------+ //| Возвращает описание флага копирования Stop Loss и 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)) ); } //+------------------------------------------------------------------+ //| Возвращает описание ограничения по депозиту (в %) | //+------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentDepositPercentDescription(void) { return CMessage::Text(MSG_SIGNAL_INFO_DEPOSIT_PERCENT)+": "+(string)this.CurrentDepositPercent()+"%"; } //+------------------------------------------------------------------+ //| Возвращает описание флага разрешения | //| на копирование сделок по подписке | //+------------------------------------------------------------------+ 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)) ); } //+------------------------------------------------------------------+ //| Возвращает описание id сигнала | //+------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentIDDescription(void) { return CMessage::Text(MSG_SIGNAL_INFO_ID)+": "+(this.CurrentID()>0 ? (string)this.CurrentID() : CMessage::Text(MSG_LIB_PROP_EMPTY)); } //+------------------------------------------------------------------+ //| Возвращает описание флага согласия | //| с условиями использования сервиса "Сигналы" | //+------------------------------------------------------------------+ 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)) ); } //+------------------------------------------------------------------+ //| Возвращает описание имени сигнала | //+------------------------------------------------------------------+ string CMQLSignalsCollection::CurrentNameDescription(void) { return CMessage::Text(MSG_SIGNAL_INFO_NAME)+": "+(this.CurrentName()!="" ? this.CurrentName() : CMessage::Text(MSG_LIB_PROP_EMPTY)); } //+------------------------------------------------------------------+
В каждом методе создаётся и возвращается строка с заголовком описания параметра и его текущим значением.
Метод, выводящий в журнал параметры настроек копирования торговых сигналов:
//+------------------------------------------------------------------+ //| Выводит в журнал параметры настроек копирования сигналов | //+------------------------------------------------------------------+ 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(""); } //+------------------------------------------------------------------+
Сначала выводится заголовок, а затем поочерёдно распечатываются все параметры настройки копирования торговых сигналов, возвращаемые соответствующими вышерассмотренными методами.
На этом создание класса-коллекции объектов-mql5-сигналов завершено.
В последующем мы возможно к нему ещё вернёмся для доработок, но пока нет возможности знать его востребованность, и мы оставим его таким.
Для связи класса-коллекции торговых сигналов с "внешним миром" нам необходимо дописать методы для работы с ним в класс главного объекта библиотеки CEngine в файле \MQL5\Include\DoEasy\Engine.mqh.
Подключим файл класса-коллекции торговых сигналов к файлу класса объекта CEngine и объявим объект класса-коллекции mql5-сигналов:
//+------------------------------------------------------------------+ //| Engine.mqh | //| Copyright 2020, MetaQuotes Software Corp. | //| https://mql5.com/ru/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://mql5.com/ru/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Включаемые файлы | //+------------------------------------------------------------------+ #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" //+------------------------------------------------------------------+ //| Класс-основа библиотеки | //+------------------------------------------------------------------+ class CEngine { private: CHistoryCollection m_history; // Коллекция исторических ордеров и сделок CMarketCollection m_market; // Коллекция рыночных ордеров и сделок CEventsCollection m_events; // Коллекция событий CAccountsCollection m_accounts; // Коллекция аккаунтов CSymbolsCollection m_symbols; // Коллекция символов CTimeSeriesCollection m_time_series; // Коллекция таймсерий CBuffersCollection m_buffers; // Коллекция индикаторных буферов CIndicatorsCollection m_indicators; // Коллекция индикаторов CTickSeriesCollection m_tick_series; // Коллекция тиковых серий CMBookSeriesCollection m_book_series; // Коллекция серий стаканов цен CMQLSignalsCollection m_signals_mql5; // Коллекция сигналов сервиса сигналов mql5.com CResourceCollection m_resource; // Список ресурсов CTradingControl m_trading; // Объект управления торговлей CPause m_pause; // Объект "Пауза" CArrayObj m_list_counters; // Список счётчиков таймера
В публичной секции класса объявим и реализуем новые методы для работы с классом-коллекцией снимков стаканов цен и методы для работы с коллекцией торговых сигналов:
//--- Обновляет серию стакана цен указанного символа void MBookSeriesRefresh(const string symbol,const long time_msc) { this.m_book_series.Refresh(symbol,time_msc); } //--- Возвращает (1) серию стакана цен указанного символа, стакан цен (2) по индексу, (3) по времени в миллисекундах 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);} //--- Возвращает объём указанного по символу и индексу стакана цен (1) на покупку, (2) на продажу long MBookVolumeBuy(const string symbol,const int index); long MBookVolumeSell(const string symbol,const int index); //--- Возвращает объём с повышенной точностью указанного по символу и индексу стакана цен (1) на покупку, (2) на продажу double MBookVolumeBuyReal(const string symbol,const int index); double MBookVolumeSellReal(const string symbol,const int index); //--- Возвращает объём указанного по символу и времени в миллисекундах стакана цен (1) на покупку, (2) на продажу long MBookVolumeBuy(const string symbol,const long time_msc); long MBookVolumeSell(const string symbol,const long time_msc); //--- Возвращает объём с повышенной точностью указанного по символу и времени в миллисекундах стакана цен (1) на покупку, (2) на продажу double MBookVolumeBuyReal(const string symbol,const long time_msc); double MBookVolumeSellReal(const string symbol,const long time_msc); //--- Возвращает (1) коллекцию сигналов сервиса сигналов mql5.com, (2) список сигналов из коллекции сигналов сервиса сигналов mql5.com CMQLSignalsCollection *GetSignalsMQL5Collection(void) { return &this.m_signals_mql5; } CArrayObj *GetListSignalsMQL5(void) { return this.m_signals_mql5.GetList(); } //--- Возвращает список (1) платных, (2) бесплатных сигналов 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) Создаёт, (2) обновляет коллекцию сигналов сервиса сигналов mql5.com bool SignalsMQL5Create(void) { return this.m_signals_mql5.CreateCollection(); } void SignalsMQL5Refresh(void) { this.m_signals_mql5.Refresh(); } //--- Осуществляет подписку на сигнал по (1) идентификатору, (2) имени сигнала 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);} //--- Осуществляет отписку от текущего сигнала bool SignalsMQL5Unsubscribe(void) { return this.m_signals_mql5.CurrentUnsubscribe(); } //--- Возвращает (1) идентификатор, (2) имя текущего сигнала, на который осуществлена подписка long SignalsMQL5CurrentID(void) { return this.m_signals_mql5.CurrentID(); } string SignalsMQL5CurrentName(void) { return this.m_signals_mql5.CurrentName(); } //--- Устанавливает процент для конвертации объема сделки bool SignalsMQL5CurrentSetEquityLimit(const double value) { return this.m_signals_mql5.CurrentSetEquityLimit(value); } //--- Устанавливает величину проскальзывания, с которой выставляются рыночные ордера при синхронизации позиций и копировании сделок bool SignalsMQL5CurrentSetSlippage(const double value) { return this.m_signals_mql5.CurrentSetSlippage(value); } //--- Устанавливает ограничения по депозиту (в %) bool SignalsMQL5CurrentSetDepositPercent(const int value) { return this.m_signals_mql5.CurrentSetDepositPercent(value); } //--- Устанавливает разрешение синхронизации без показа диалога подтверждения bool SignalsMQL5CurrentSetConfirmationsDisableON(void) { return this.m_signals_mql5.CurrentSetConfirmationsDisableON();} //--- Устанавливает запрет синхронизации без показа диалога подтверждения bool SignalsMQL5CurrentSetConfirmationsDisableOFF(void) { return this.m_signals_mql5.CurrentSetConfirmationsDisableOFF();} //--- Устанавливает разрешение копирования Stop Loss и Take Profit bool SignalsMQL5CurrentSetSLTPCopyON(void) { return this.m_signals_mql5.CurrentSetSLTPCopyON(); } //--- Устанавливает запрет копирования Stop Loss и Take Profit bool SignalsMQL5CurrentSetSLTPCopyOFF(void) { return this.m_signals_mql5.CurrentSetSLTPCopyOFF(); } //--- Устанавливает разрешение на копирование сделок по подписке bool SignalsMQL5CurrentSetSubscriptionEnableON(void) { return this.m_signals_mql5.CurrentSetSubscriptionEnableON(); } //--- Устанавливает запрет на копирование сделок по подписке bool SignalsMQL5CurrentSetSubscriptionEnableOFF(void) { return this.m_signals_mql5.CurrentSetSubscriptionEnableOFF();} //--- Выводит в журнал (1) полное, (2) краткое описание коллекции, (3) параметры настроек копирования сигналов 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();} //--- Возвращает (1) коллекцию буферов, (2) список буферов из коллекции
Реализованные методы возвращают результат вызова одноимённых методов соответствующих коллекций.
Рассмотрим реализацию методов, возвращающих указанные объёмы указанных снимков стаканов цен:
//+------------------------------------------------------------------+ //| Возвращает объём на покупку стакана цен, | //| указанного по символу и индексу | //+------------------------------------------------------------------+ long CEngine::MBookVolumeBuy(const string symbol,const int index) { CMBookSnapshot *mbook=this.GetMBook(symbol,index); return(mbook!=NULL ? mbook.VolumeBuy() : 0); } //+------------------------------------------------------------------+ //| Возвращает объём на продажу стакана цен, | //| указанного по символу и индексу | //+------------------------------------------------------------------+ long CEngine::MBookVolumeSell(const string symbol,const int index) { CMBookSnapshot *mbook=this.GetMBook(symbol,index); return(mbook!=NULL ? mbook.VolumeSell() : 0); } //+------------------------------------------------------------------+ //| Возвращает объём на покупку с повышенной точностью | //| стакана цен, указанного по символу и индексу | //+------------------------------------------------------------------+ double CEngine::MBookVolumeBuyReal(const string symbol,const int index) { CMBookSnapshot *mbook=this.GetMBook(symbol,index); return(mbook!=NULL ? mbook.VolumeBuyReal() : 0); } //+------------------------------------------------------------------+ //| Возвращает объём на продажу с повышенной точностью | //| стакана цен,указанного по символу и индексу | //+------------------------------------------------------------------+ double CEngine::MBookVolumeSellReal(const string symbol,const int index) { CMBookSnapshot *mbook=this.GetMBook(symbol,index); return(mbook!=NULL ? mbook.VolumeSellReal() : 0); } //+------------------------------------------------------------------+ //| Возвращает объём на покупку стакана цен, | //| указанного по символу и времени в миллисекундах | //+------------------------------------------------------------------+ long CEngine::MBookVolumeBuy(const string symbol,const long time_msc) { CMBookSnapshot *mbook=this.GetMBook(symbol,time_msc); return(mbook!=NULL ? mbook.VolumeBuy() : 0); } //+------------------------------------------------------------------+ //| Возвращает объём на продажу стакана цен, | //| указанного по символу и времени в миллисекундах | //+------------------------------------------------------------------+ long CEngine::MBookVolumeSell(const string symbol,const long time_msc) { CMBookSnapshot *mbook=this.GetMBook(symbol,time_msc); return(mbook!=NULL ? mbook.VolumeSell() : 0); } //+------------------------------------------------------------------+ //| Возвращает объём на покупку с повышенной точностью | //| стакана цен, указанного по символу и времени в миллисекундах | //+------------------------------------------------------------------+ double CEngine::MBookVolumeBuyReal(const string symbol,const long time_msc) { CMBookSnapshot *mbook=this.GetMBook(symbol,time_msc); return(mbook!=NULL ? mbook.VolumeBuyReal() : 0); } //+------------------------------------------------------------------+ //| Возвращает объём на продажу с повышенной точностью | //| стакана цен,указанного по символу и времени в миллисекундах | //+------------------------------------------------------------------+ double CEngine::MBookVolumeSellReal(const string symbol,const long time_msc) { CMBookSnapshot *mbook=this.GetMBook(symbol,time_msc); return(mbook!=NULL ? mbook.VolumeSellReal() : 0); } //+------------------------------------------------------------------+
Здесь всё просто. Логика всех методов идентична: сначала получаем из списка-коллекции объект-снимок стакана цен по символу и индексу или времени в миллисекундах с помощью ранее реализованных методов GetMBook(), затем возвращаем соответствующий методу объём стакана цен из полученного объекта-снимка стакана цен, либо ноль, если объект получить не удалось.
Это все доработки и изменения на сегодня.
Тестирование
Протестируем создание коллекции Сигналов MQL5.com. Тестировать будем так:
Получим полный список из базы Сигналов, выведем список только бесплатных сигналов, затем найдём в этом списке самый прибыльный сигнал и подпишемся на него. При удачном оформлении подписки выведем параметры подписанного сигнала и параметры копирования торговых сигналов, установленные при подписке на сигнал. На следующем тике отпишемся от подписанного сигнала.
Для тестирования возьмём советник из прошлой статьи
и сохраним его в новой папке \MQL5\Experts\TestDoEasy\Part66\ под новым именем TestDoEasyPart66.mq5.
В список входных параметров советника добавим параметр настройки, позволяющий выбрать необходимость работы с сервисом Сигналы 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
В прошлой статье мы все проверки работы с сигналами делали в обработчике OnInit() советника. Сегодня будем работать уже в OnTick().
Поэтому удалим уже ненужный прошлый тестовый блок кода из обработчика OnInit():
CArrayObj *list=new CArrayObj(); if(list!=NULL) { //--- запрашиваем общее количество сигналов в базе int total=SignalBaseTotal(); //--- цикл по всем сигналам for(int i=0;i<total;i++) { //--- выбираем сигнал для дальнейшей работы 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; } } //--- выводим все прибыльные бесплатные сигналы с ненулевым количеством подписчиков 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; //--- Самый первый подходящий сигнал распечатываем полностью в журнале if(!done) { signal.Print(); done=true; } //--- Для остальных выводим краткие описания else signal.PrintShort(); } delete list; } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
В обработчик OnTick() впишем новый тестовый блок кода, в котором выполняются все условия теста, оговорённые нами в самом начале этого раздела:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Удаление графических объектов советника по префиксу имени объектов ObjectsDeleteAll(0,prefix); Comment(""); //--- Деинициализация библиотеки engine.OnDeinit(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Обработка события NewTick в библиотеке engine.OnTick(rates_data); //--- Если работа в тестере if(MQLInfoInteger(MQL_TESTER)) { engine.OnTimer(rates_data); // Работа в таймере PressButtonsControl(); // Контроль нажатия кнопок engine.EventsHandling(); // Работа с событиями } //--- Если установлен флаг трейлинга if(trailing_on) { TrailingPositions(); // Трейлинг позиций TrailingOrders(); // Трейлинг отложенных ордеров } //--- Поиск доступных сигналов в базе и проверка возможности подписаться на сигнал по его имени static bool done=false; //--- Если первый запуск и работа с сигналами разрешена в пользовательских настройках советника if(InpUseMqlSignals && !done) { //--- Выводим в журнал список всех бесплатных сигналов Print(""); engine.GetSignalsMQL5Collection().PrintShort(true,false,true); //--- Получаем список только бесплатных сигналов CArrayObj *list=engine.GetListSignalsMQL5Free(); //--- Если список получен if(list!=NULL) { //--- Находим в списке сигнал с максимальным приростом в процентах int index_max_gain=CSelect::FindMQLSignalMax(list,SIGNAL_MQL5_PROP_GAIN); CMQLSignal *signal_max_gain=list.At(index_max_gain); //--- Если сигнал найден if(signal_max_gain!=NULL) { //--- Выведем в журнал полное описание сигнала signal_max_gain.Print(); //--- Если удалось подписаться на сигнал if(engine.SignalsMQL5Subscribe(signal_max_gain.ID())) { //--- Устанавливаем параметры подписки //--- Разрешаем копирование сделок по подписке engine.SignalsMQL5CurrentSetSubscriptionEnableON(); //--- Устанавливаем запрет синхронизации без показа диалога подтверждения engine.SignalsMQL5CurrentSetConfirmationsDisableOFF(); //--- Устанавливаем разрешение копирования Stop Loss и Take Profit engine.SignalsMQL5CurrentSetSLTPCopyON(); //--- Устанавливаем величину проскальзывания, с которой выставляются рыночные ордера при синхронизации позиций и копировании сделок engine.SignalsMQL5CurrentSetSlippage(2); //--- Устанавливаем процент для конвертации объема сделки engine.SignalsMQL5CurrentSetEquityLimit(50); //--- Устанавливаем ограничения по депозиту (в %) engine.SignalsMQL5CurrentSetDepositPercent(70); //--- Выводим в журнал параметры подписки engine.SignalsMQL5CurrentSubscriptionParameters(); } } } done=true; return; } //--- Если есть подписка на сигнал - отписываемся от него if(engine.SignalsMQL5CurrentID()>0) { engine.SignalsMQL5Unsubscribe(); } //--- } //+------------------------------------------------------------------+
Весь новый блок кода достаточно подробно прокомментирован. Если по нему возникли какие-либо вопросы, то их можно задать в обсуждении к статье.
В функции инициализации библиотеки OnInitDoEasy() впишем блок кода, в котором создаётся список-коллекция торговых сигналов и устанавливается флаг разрешения копирования торговых сигналов по подписке:
//--- Создание тиковых серий всех используемых символов engine.TickSeriesCreateAll(); //--- Проверка созданных тиковых серий - выводим в журнал описания всех созданных тиковых серий engine.GetTickSeriesCollection().Print(); //--- Проверка созданных серий стаканов цен - выводим в журнал описания всех созданных серий стаканов цен engine.GetMBookSeriesCollection().Print(); //--- Создание коллекции сигналов сервиса сигналов mql5.com //--- Если работа с сигналами разрешена и коллекция сигналов создана if(InpUseMqlSignals && engine.SignalsMQL5Create()) { //--- Устанавливаем разрешение на копирование сделок по подписке engine.SignalsMQL5CurrentSetSubscriptionEnableON(); //--- Проверка созданных объектов-mql5-сигналов сервиса сигналов - выводим в журнал короткое описание коллекции engine.SignalsMQL5PrintShort(); } //--- Если работа с сигналами не разрешена или не удалось создать коллекцию сигналов - //--- устанавливаем запрет на копирование сделок по подписке else engine.SignalsMQL5CurrentSetSubscriptionEnableOFF(); //--- Создание тестовых файлов ресурсов
Скомпилируем советник и запустим его на графике символа, предварительно задав в настройках работу на текущем символе/таймфрейме и установив флаг необходимости работы с торговыми сигналами сервиса Сигналы MQL5.com:
Во вкладке "Общие" окна настроек советника обязательно нужно установить галочку на пункте "Разрешить изменение настроек Сигналов":
Без этого советнику будет запрещено работать с сервисом Сигналов MQL5.com.
После запуска советника, в журнал будет выведено сообщение об успешном создании коллекции сигналов и её краткое описание:
Коллекция сигналов сервиса сигналов mql5.com создана успешно Коллекция сигналов сервиса сигналов mql5.com: - Бесплатных сигналов: 195, Платных сигналов: 805
Далее будет выведен полный список бесплатных сигналов. Так как их много, то приведу в пример только часть:
Коллекция сигналов сервиса сигналов mql5.com: - Сигнал "GBPUSD EXPERT 23233". Логин автора: mbt_trader, ID 919099, Прирост: 3.30, Просадка: 11.92, Цена: 0.00, Подписчиков: 0 - Сигнал "Willian". Логин автора: Desg, ID 917396, Прирост: 12.69, Просадка: 15.50, Цена: 0.00, Подписчиков: 0 - Сигнал "VahidVHZ1366". Логин автора: 39085485, ID 921427, Прирост: 34.36, Просадка: 12.84, Цена: 0.00, Подписчиков: 0 - Сигнал "Vikings". Логин автора: Myxx, ID 921040, Прирост: 7.05, Просадка: 2.22, Цена: 0.00, Подписчиков: 2 - Сигнал "VantageFX Sunphone Dragon". Логин автора: sunphone, ID 916421, Прирост: 537.89, Просадка: 39.06, Цена: 0.00, Подписчиков: 21 - Сигнал "Forex money maker free". Логин автора: Yggdrasills, ID 916328, Прирост: 44.66, Просадка: 61.15, Цена: 0.00, Подписчиков: 0 ... ... ... - Сигнал "Nine Pairs ST". Логин автора: ebi.pilehvar, ID 935603, Прирост: 25.92, Просадка: 26.41, Цена: 0.00, Подписчиков: 2 - Сигнал "FBS140". Логин автора: mohammeeeedali, ID 949720, Прирост: 42.14, Просадка: 23.11, Цена: 0.00, Подписчиков: 2 - Сигнал "StopTheFourthAddition". Логин автора: pinheirodps, ID 934990, Прирост: 41.78, Просадка: 28.03, Цена: 0.00, Подписчиков: 2 - Сигнал "The art of Forex". Логин автора: Myxx, ID 801685, Прирост: 196.39, Просадка: 40.95, Цена: 0.00, Подписчиков: 59 - Сигнал "Bongsanmaskdance1803". Логин автора: kim25801863, ID 936062, Прирост: 12.53, Просадка: 10.31, Цена: 0.00, Подписчиков: 0 - Сигнал "Prospector Scalper EA". Логин автора: robots4forex, ID 435626, Прирост: 334.76, Просадка: 43.93, Цена: 0.00, Подписчиков: 215 - Сигнал "ADS MT5". Логин автора: vluxus, ID 478235, Прирост: 295.68, Просадка: 40.26, Цена: 0.00, Подписчиков: 92
Затем нам будет выведено полное описание найденного сигнала с максимальным приростом в процентах и сообщение об успешной подписке на него:
============= Начало списка параметров (Сигнал сервиса сигналов mql5.com) ============= Тип счета: Демонстрационный счёт Дата публикации: 2020.07.02 16:29 Дата начала мониторинга: 2020.07.02 16:29 Дата последнего обновления торговой статистики: 2021.03.07 15:11 ID: 784584 Плечо торгового счета: 33 Результат торговли в пипсах: -19248988 Позиция в рейтинге сигналов: 872 Количество подписчиков: 6 Количество трейдов: 1825 Состояние подписки счёта на этот сигнал: Нет ------ Баланс счета: 12061.98 Средства на счете: 12590.32 Прирост счета в процентах: 1115.93 Максимальная просадка: 70.62 Цена подписки на сигнал: 0.00 Значение ROI (Return on Investment) сигнала в %: 1169.19 ------ Логин автора: "tradewai.com" Наименование брокера (компании): "MetaQuotes Software Corp." Сервер брокера: "MetaQuotes-Demo" Имя: "Tradewai" Валюта счета: "USD" ============= Конец списка параметров (Сигнал сервиса сигналов mql5.com) ============= Осуществлена подписка на сигнал ID 784584 "Tradewai"
После этого будут выведены параметры подписки:
============= Параметры копирования сигнала ============= Разрешение на работу с сигналами для программы: Да Согласие с условиями использования сервиса "Сигналы": Да Разрешение на копирование сделок по подписке: Да Разрешение синхронизации без показа диалога подтверждения: Нет Копирование Stop Loss и Take Profit: Да Проскальзывание, с которым выставляются рыночные ордера при синхронизации позиций и копировании сделок: Спред * 2.00 Процент для конвертации объема сделки: 50.00% Ограничение по депозиту: 70% Ограничение по средствам для сигнала: 7.00% Идентификатор сигнала: 784584 Имя сигнала: Tradewai
а при наступлении следующего тика мы получим сообщение об успешной отписке от сигнала.
Осуществлена отписка от сигнала ID 784584 "Tradewai"
Что дальше
В следующей статье начнём разрабатывать функционал библиотеки для работы с чартами — графиками символов.
Ниже прикреплены все файлы текущей версии библиотеки и файл тестового советника для MQL5. Их можно скачать и протестировать всё самостоятельно.
Хочу отметить, что тест работы с сигналами в тестовом советнике является именно тестом работы с сигналами, и не пригоден для его использования в том виде, в котором он реализован в прилагаемом советнике. Прошу учитывать, что это всего лишь пример без какой-либо полезной нагрузки.
Приведённый в советнике пример даёт лишь понимание общего направления действий при реализации собственных разработок на основе библиотеки и её классов для работы с сервисом Сигналов MQL5.com.
При возникновении вопросов, замечаний и пожеланий, вы можете озвучить их в комментариях к статье.
*Статьи этой серии:
Работа с ценами в библиотеке DoEasy (Часть 62): Реалтайм-обновление тиковых серий, подготовка к работе со стаканом цен
Работа с ценами в библиотеке DoEasy (Часть 63): Стакан цен, класс абстрактной заявки стакана цен
Работа с ценами в библиотеке DoEasy (Часть 64): Стакан цен, классы объекта-снимка и объекта-серии снимков стакана цен
Работа с ценами и Сигналами в библиотеке DoEasy (Часть 65): Коллекция стаканов и класс для работы с Сигналами MQL5.com





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Почему таг стоит "торговые системы" в разделе статей? здесь же нет ТС
Весь раздел "торговые системы" забит вашими статьями, по итогу
Потому, что библиотека создаётся в частности и для создания торговых систем.
Потому, что библиотека создаётся в частности и для создания торговых систем.
в этом есть некоторое логическое противоречие
в этом есть некоторое логическое противоречие
Boa noite!
Saudações aqui do Brasil.
Estou tendo impedimento na hora de compilar o código e como meu conhecimento de mql5 é muito básico, resta pedir sua ajuda para superar os problemas na compilação...não sei resolver.
Quero aproveitar e parabenizá-lo pelo trabalho brilhante, seus códigos me ajudam muito.
Boa noite!
Saudações aqui do Brasil.
Estou tendo impedimento na hora de compilar o código e como meu conhecimento de mql5 é muito básico, resta pedir sua ajuda para superar os problemas na compilação...não sei resolver.
Quero aproveitar e parabenizá-lo pelo trabalho brilhante, seus códigos me ajudam muito.
В файле Trading.mqh нужно некоторые методы перенести в защищённую секцию - чтобы к ним был доступ из производных классов. Сейчас же они находятся в приватной секции класса. Эта ошибка была допущена мною по невнимательности, но старый компилятор её пропустил. После обновления терминала эта ошибка стала обнаруживаться.
В строках 84 - 89 файла Trading.mqh нужно сделать такие изменения:
In the Trading.mqh file, some methods need to be moved to a protected section so that they can be accessed from derived classes. Now they are in the private section of the class. This mistake was made by me inadvertently, but the old compiler missed it. After updating the terminal, this error began to be detected.
In lines 84 - 89 of the Trading.mqh file, you need to make the following changes:
и в строках 155 - 181 сделать аналогичные правки:
and in lines 155 - 181 make similar edits:После этого всё будет компилироваться.
Исправленный файл прилагаю к этому посту.
After that, everything will compile.
The corrected file is attached to this post.