- Получение списков доступных символов и Обзора рынка
- Редактирование списка Обзора рынка
- Проверка символа на существование
- Проверка актуальности данных по символу
- Получение последнего тика по символу
- Расписания торговых и котировочных сессий
- Маржинальные коэффициенты по символу
- Обзор функций получения свойств символа
- Проверка состояния символа
- Тип цены для построения графиков по символу
- Базовая, котировочная и маржинальная валюты инструмента
- Точность представления и шаг изменения цен
- Разрешенные объемы торговых операций
- Разрешения на торговлю
- Торговые условия и режимы исполнения приказов по символу
- Маржинальные требования
- Правила истечения сроков отложенных ордеров
- Спреды и отступы приказов от текущей цены
- Получение величины свопов
- Текущая рыночная информация (тик)
- Описательные свойства символов
- Глубина стакана цен
- Свойства пользовательских символов
- Специфические свойства (биржа, срочный рынок, облигации)
Базовая, котировочная и маржинальная валюты инструмента
Как известно, одними из самых важных свойств каждого финансового инструмента являются его рабочие валюты:
- базовая валюта, в которой выражается покупаемый или продаваемый актив (для инструментов Forex);
- валюта расчета прибыли (котирования);
- валюта расчета залога;
MQL-программа может получить названия этих валют с помощью функции SymbolInfoString и трех свойств из следующей таблицы.
Идентификатор |
Описание |
---|---|
SYMBOL_CURRENCY_BASE |
Базовая валюта |
SYMBOL_CURRENCY_PROFIT |
Валюта прибыли |
SYMBOL_CURRENCY_MARGIN |
Валюта, в которой вычисляются залоговые средства |
С помощью них удобно анализировать инструменты Forex, в имена которых многие брокеры добавляют различные префиксы и суффиксы, а также биржевые инструменты. В частности, алгоритм сможет найти символ для получения кросс-курса двух заданных валют или подобрать корзину индексов с заданной общей валютой котирования.
Поскольку поиск инструментов согласно неким требованиям является частой задачей, создадим класс SymbolFilter (SymbolFilter.mqh) для построения списка подходящих символов и их избранных свойств. В дальнейшем используем этот класс не только для анализа валют, но и других характеристик.
Сначала рассмотрим упрощенную версию, а потом дополним её удобным функционалом.
В разработке воспользуемся уже готовыми вспомогательными средствами: ассоциативным массивом-картой (MapArray.mqh) для хранения пар ключ-значение выбранных типов и монитором свойств символа (SymbolMonitor.mqh).
#include <MQL5Book/MapArray.mqh>
|
Для упрощения инструкций по накоплению результатов работы в массивах применим усовершенствованную версию маркоса PUSH, уже встречавшегося ранее в примерах, а также его вариант EXPAND для многомерных массивов (простое присваивание в этом случае невозможно).
#define PUSH(A,V) (A[ArrayResize(A, ArraySize(A) + 1, ArraySize(A) * 2) - 1] = V)
|
Объект класса SymbolFilter должен иметь хранилище значений свойств, по которым программист желает фильтровать символы. Поэтому опишем в классе 3 массива MapArray для целочисленных, вещественных и строковых свойств.
class SymbolFilter
|
Установка требуемых свойств фильтра производится с помощью перегруженных методов let.
public:
|
Обратите внимание, что методы возвращают указатель на сам фильтр, что позволяет записывать условия в виде цепочки: например, если ранее в коде был описан объекта f типа SymbolFilter, то для наложения двух условий на тип цены и название валюты прибыли можно написать:
f.let(SYMBOL_CHART_MODE, SYMBOL_CHART_MODE_LAST).let(SYMBOL_CURRENCY_PROFIT, "USD"); |
Формирование массива символов, удовлетворяющих условиям, выполняется объектом-фильтром в нескольких вариантах метода select, самый простой из которых представлен ниже (другие варианты рассмотрим позднее).
Параметр watch определяет контекст поиска символов: среди выбранных в Обзор рынка (true) или всех доступных (false). Выходной массив symbols будет заполнен названиями походящих символов. Структура кода внутри метода нам уже знакома: здесь организован цикл по символам, для каждого из которых создается объект-монитор m.
void select(const bool watch, string &symbols[]) const
|
Именно с помощью монитора мы можем унифицированно получить значение любого свойства. Проверка соответствия свойств текущего символа с сохраненным набором условий в массивах longs, doubles, strings делегируется вспомогательному методу match. Все запрошенные свойства должны совпасть, чтобы имя символа было сохранено в выходном массиве symbols.
В простейшем случае реализация метода match такова (впоследствии он будет изменен).
protected:
|
Если хоть одно из значений в массиве data не совпадает с соответствующим свойством символа, метод возвращает false. Если все свойства совпали (или условий для свойств данного типа нет), метод возвращает true.
Сравнение двух значений выполняется методом equal. Учитывая тот факт, что среди свойств могут быть свойства типа double, реализация не так проста, как можно было бы подумать.
template<typename V>
|
Для типа double выражение v1 == v2 может не сработать для близких чисел, в связи с чем следует учитывать точность вещественного типа DBL_EPSILON. Это делается в отдельном методе eps, перегруженном раздельно для типа double и всех остальных типов за счет шаблона.
static bool eps(const double v1, const double v2)
|
При равенстве значений любых типов кроме double шаблонный метод eps просто не будет вызван, а во всех иных случаях (в том числе и при различии значений) он возвращает false, как и требовалось (таким образом, работать будет только условие v1 == v2).
Вышеописанный вариант фильтра позволяет проверять свойства только на равенство значениям. Однако на практике часто требуется анализировать условия на неравенство, а также на больше/меньше. В связи с этим в классе SymbolFilter определено перечисление IS с основными операциями сравнения (при желании его можно дополнить).
class SymbolFilter
|
Для каждого свойства из перечислений ENUM_SYMBOL_INFO_INTEGER, ENUM_SYMBOL_INFO_DOUBLE, ENUM_SYMBOL_INFO_STRING требуется сохранить не только искомое значение свойства (вспоминаем про ассоциативные массивы longs, doubles, strings), но и способ сравнения из нового перечисления IS.
Поскольку элементы стандартных перечислений имеют непересекающиеся значения (здесь есть одно исключение, связанное с объемами, но оно не критично), имеет смысл зарезервировать под способ сравнения один общий массив-карту conditions. При этом встает вопрос, какой тип выбрать для ключа карты, чтобы технически "объединить" разные перечисления. Для этого потребовалось описать фиктивное перечисление ENUM_ANY — оно лишь обозначает некий тип обобщенного перечисления. Напомним, что все перечисления имеют внутреннее представление, эквивалентное целому int, и потому могут приводиться одно к другому.
enum ENUM_ANY
|
Теперь мы можем дополнить все методы let, устанавливающие искомое значение свойства, входным параметром cmp, который определяет способ сравнения. По умолчанию он задает проверку на равенство (EQUAL).
SymbolFilter *let(const ENUM_SYMBOL_INFO_INTEGER property, const long value,
|
Здесь представлен вариант для целочисленных свойств. Остальные две перегрузки изменяются аналогично.
С учетом новой информации о разных способах сравнения и одновременного избавления от разных типов ключей в массивах-картах мы модифицируем метод match. В нем для каждого заданного свойства, по ключу в массиве-карте data извлекается условие из массива conditions и с помощью оператора switch выполняются соответствующие проверки.
template<typename V>
|
Новый шаблонный метод greater реализован тривиально.
template<typename V>
|
Теперь вызов метода match можно записать более кратко, так как единственный оставшийся тип шаблона V автоматически определяется по передаваемому аргументу data (а это один из массивов longs, doubles или strings).
void select(const bool watch, string &symbols[]) const
|
Это еще не окончательная версия класса SymbolFilter, но мы уже можем проверить его в действии.
Создадим скрипт SymbolFilterCurrency.mq5, способный фильтровать символы по свойствам базовой валюты и валюты прибыли — в данном случае "USD". Параметр MarketWatchOnly по умолчанию задает поиск только по Обзору рынка.
#include <MQL5Book/SymbolFilter.mqh>
|
Допустим, что мы хотим найти инструменты Forex, которые имеют прямые котировки, то есть в их названиях "USD" фигурирует в начале. Чтобы не зависеть от особенностей формирования названий у конкретного брокера, воспользуемся свойством SYMBOL_CURRENCY_BASE. Именно оно содержит первую валюту.
Запишем условие, чтобы базовая валюта символа равнялась "USD", и применим фильтр.
f.let(SYMBOL_CURRENCY_BASE, "USD")
|
Полученный массив выводится в журнал.
===== Base is USD =====
|
Как видно, в массив попали не только Forex-символы, у которых "USD" идет в начале тикера, но также индекс S&P500 и товар (нефть). Два последних символа котируются в долларах, но и базовая валюта у них такая же. В то же время у Forex-символов валюта котирования (она же валюта прибыли) идет второй и отличается от "USD". Это позволяет дополнить фильтр таким образом, чтобы не-Forex-символы перестали ему соответствовать.
Очистим массив, добавим в фильтр условие, чтобы валюта прибыли не равнялась "USD", и снова запросим подходящие символы (прежнее условие сохранилось в объекте f).
...
|
На этот раз в журнале выведены действительно только искомые символы.
===== Base is USD and Profit is not USD =====
|