Русский

Учебник по MQL4  Создание обычной программы  Учёт ордеров


Учёт ордеров


Ранее упоминалось, что каких-либо жёстких правил для составления алгоритмов программ не существует. Вместе с тем, подавляющее большинство алгоритмов предполагает принятие торговых решений в зависимости от текущего состояния ордеров. В одних случаях, например, для открытия рыночного ордера требуется, чтобы на момент осуществления торговой операции других рыночных ордеров не было. В других случаях, для установки отложенного ордера необходимым условием может являться отсутствие стоп-приказов на рыночном ордере. Известны также алгоритмы, предполагающие установку одновременно двух разнонаправленных отложенных ордеров.

Чтобы удовлетворить требования той или иной тактики или стратегии к моменту принятия торгового решения, необходимо знать текущее состояние: какие рыночные и отложенные ордера имеются и какие у них характеристики. Для этого можно использовать один из двух вариантов решения.

В соответствии с первым вариантом необходимый фрагмент программного кода (в котором выполняется анализ ордеров) прописывается непосредственно в том месте программы, где нужно выяснить текущий набор ордеров и их характеристики. Такое решение технически осуществимо, но оказывается неэффективным, когда необходимо внести изменения в алгоритм. В этом случае программист вынужден анализировать все места программы, где анализируется состояние ордеров, и вносить изменения в каждом месте. Второй, более эффективный вариант решения, заключается в том, чтобы один раз создать универсальную функцию учёта ордеров и использовать её всякий раз, когда требуется обновить информацию о текущем состоянии ордеров. Такое решение, с одной стороны, позволяет значительно сократить код программы, а с другой стороны, предоставляет программисту возможность использовать готовую функцию при составлении других программ.

Для того чтобы правильно составить функцию учёта ордеров, необходимо решить, какие параметры нужно учитывать. В большинстве случаев для принятия торговых решений требуются значения следующих параметров:

  • общее количество ордеров;
  • количество ордеров каждого типа (например, сколько имеется ордеров Buy, сколько SellStop, BuyLimit и т.д.);
  • все характеристики каждого из ордеров (номер ордера, StopLoss и TakeProfit ордера, количество лотов и т.д.).

Указанная информация должна быть доступна другим функциям, а именно тем, в которых эта информация обрабатывается. По этой причине все параметры, характеризующие состояние ордеров, являются значениями глобальных массивов. Всего для учёта ордеров предусмотрено три массива:

  • массив текущих ордеров Mas_Ord_New, содержащий сведения обо всех характеристиках всех рыночных и отложенных ордеров, имеющихся на текущий момент, а именно, в период последнего исполнения функции;
  • массив старых ордеров Mas_Ord_Old, содержащий сведения обо всех характеристиках всех рыночных и отложенных ордеров, имеющихся на момент предыдущего исполнения функции;
  • массив Mas_Tip, значениями которого являются количества ордеров различных типов (на текущий момент).

Массивы Mas_Ord_New и Mas_Ord_Old подобны и имеют одинаковую размерность; разница между ними заключается лишь в том, что первый из них отражает текущее состояние ордеров, а второй - предшествующее. Рассмотрим детально, какие значения содержатся в элементах этих массивов.

Таблица 4. Соответствие элементов массивов Mas_Ord_New и Mas_Ord_Old характеристикам ордеров.


Не опред. Курс открытия StopLoss TakeProfit Номер ордера Колич. лотов Тип ордера Magic Number Коммент.
Индексы 0 1 2 3 4 5 6 7 8
0 2.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
1 0.0 1.2583 1.2600 1.2550 123456.0 1.4 1.0 1177102416.0 1.0
2 0.0 1.2450 1.2580 1.2415 123458.0 2.5 2.0 1177103358.0 0.0
3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
. . . 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
30 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0

Первый индекс массива (строки) определяет порядковый номер ордера в массиве. Характеристики первого обнаруженного ордера (среди открытых рыночных и установленных отложенных ордеров) заносятся в первую строку массива, второго ордера - во вторую строку и т.д. Размер массива по первому индексу равен 31, таким образом, массив предназначен для хранения информации максимум о тридцати ордерах, одновременно присутствующих в торговле по одному торговому счёту. В случае, если торговая стратегия допускает наличие одновременно более тридцати ордеров, то при объявлении массива необходимо указать соответствующее значение для первого индекса. (В подавляющем большинстве случаев значение 30 значительно превышает действительную потребность, которая может составлять от 2 до 10-15. Здесь для примера используется значение 30, принятое с большим запасом, в предположении, что функция может использоваться и в случае реализации своеобразной торговой стратегии).

Второй индекс массива (столбцы) соответствует характеристикам ордеров. Каждый элемент массива со вторым индексом, равным 1, содержит значение курса открытия ордера, с индексом 2 - значение StopLoss ордера, 3 - TakeProfit ордера и т.д. (см. Таблицу 4). Элемент массива с индексом [0][0] имеет значение, равное общему количеству ордеров, содержащихся в массиве. Все элементы массива с первым или вторым индексом, равным 0, не используются (кроме элемента с индексом [0][0]).

В таблице 4 показано состояние массива, содержащего информацию о двух ордерах, в некоторый момент времени одновременно присутствующих в торговле. Элемент массива Mas_Ord_New[0][0] имеет значение 2.0 - общее количество ордеров - два. Элементы первой строки массива содержат значения характеристик рыночного ордера Sell (Mas_Ord_New[1][6] = 1.0, см. Типы торговых операций), открытого на 1.4 лота (Mas_Ord_New[1][5] =1.4), имеющего номер 123456 (Mas_Ord_New[1][4] =123456.0). Значение элемента Mas_Ord_New[1][8] =1.0 означает, что этот ордер имеет непустой комментарий. Во второй строке массива содержатся значения, характеризующие второй ордер. В частности, элемент массива Mas_Ord_New[2][6] имеет значение 2.0, - значит, это ордер BuyLimit.

Массив Mas_Tip отражает количество ордеров каждого типа. Значения индексов этого массива поставлены в соответствие типам торговых операций (см. Типы торговых операций). Это означает, что элемент массива Mas_Tip с индексом 0 содержит количество одновременно присутствующих в торговле рыночных ордеров типа Buy, с индексом 1 - ордеров типа Sell, с индексом 2 - типа BuyLimit и т.д. Для ситуации, отражённой в таблице 4, элементы массива Mas_Tip будут иметь следующие значения:

Таблица 5. Соответствие элементов массива Mas_Tip количеству ордеров различных типов.


Buy Sell BuyLimit SellLimit BuyStop SellStop
Индекс 0 1 2 3 4 5
Значение 0 1 1 0 0 0

В данном случае значения элементов массива Mas_Tip означают следующее: Mas_Tip[1] равно 1, значит, в торговле имеется один ордер Sell; Mas_Tip[2] также равно 1, значит, в торговле есть один отложенный ордер BuyLimit. Остальные элементы массива имеют нулевые значения, значит ордеров этого типа в торговле нет. В случае если в торговле присутствуют одновременно несколько ордеров одного типа, то соответствующий элемент массива будет иметь значение, равное количеству таких ордеров. Например, если в торговле имеется три ордера BuyStop, то элемент Mas_Tip[4] будет иметь значение 3.

Предлагаемая здесь функция учёта ордеров Terminal() оформлена в виде включаемого файла Terminal.mqh.

Пользовательская функция Terminal()

int Terminal()

Функция выполняет учёт рыночных и отложенных ордеров. В результате исполнения функции изменяются значения следующих глобальных массивов:

  • Mas_Ord_New - массив характеристик ордеров, имеющихся на момент исполнения функции;
  • Mas_Ord_Old - массив характеристик ордеров, имеющихся на момент предыдущего исполнения функции;
  • Mas_Tip - массив количества ордеров всех типов.

Включаемый файл Terminal.mqh, содержащий описание функции учёта ордеров Terminal():

//--------------------------------------------------------------------
// Terminal.mqh
// Предназначен для использования в качестве примера в учебнике MQL4.
//--------------------------------------------------------------- 1 --
// Функция учёта ордеров
// Глобальные переменные:
// Mas_Ord_New[31][9] // Массив ордеров последний известный
// Mas_Ord_Old[31][9] // Массив ордеров предыдущий (старый)
// 1й индекс = порядковый номер ордера
// [][0] не определяется
// [][1] курс откр. ордера (абс.знач.курса)
// [][2] StopLoss ордера (абс.знач.курса)
// [][3] TakeProfit ордера (абс.знач.курса)
// [][4] номер ордера
// [][5] колич. лотов орд. (абс.знач.курса)
// [][6] тип орд. 0=B,1=S,2=BL,3=SL,4=BS,5=SS
// [][7] магическое число ордера
// [][8] 0/1 факт наличия комментария
// Mas_Tip[6] // Массив колич. ордеров всех типов
// [] тип орд: 0=B,1=S,2=BL,3=SL,4=BS,5=SS
//--------------------------------------------------------------- 2 --
int Terminal()
{
int Qnt=0; // Счётчик количества ордеров

//--------------------------------------------------------------- 3 --
ArrayCopy(Mas_Ord_Old, Mas_Ord_New);// Сохраняем предыдущую историю
Qnt=0; // Обнуление счётчика ордеров
ArrayInitialize(Mas_Ord_New,0); // Обнуление массива
ArrayInitialize(Mas_Tip, 0); // Обнуление массива
//--------------------------------------------------------------- 4 --
for(int i=0; i<OrdersTotal(); i++) // По рыночн. и отлож. ордерам
{
if((OrderSelect(i,SELECT_BY_POS)==true) //Если есть следующ.
&&
(OrderSymbol()==Symbol())) //.. и наша вал.пара
{
//------------------------------------------------------ 5 --
Qnt++; // Колич. ордеров
Mas_Ord_New[Qnt][1]=OrderOpenPrice(); // Курс открытия орд
Mas_Ord_New[Qnt][2]=OrderStopLoss(); // Курс SL
Mas_Ord_New[Qnt][3]=OrderTakeProfit(); // Курс ТР
Mas_Ord_New[Qnt][4]=OrderTicket(); // Номер ордера
Mas_Ord_New[Qnt][5]=OrderLots(); // Количество лотов
Mas_Tip[OrderType()]++; // Кол. ордеров типа
Mas_Ord_New[Qnt][6]=OrderType(); // Тип ордера
Mas_Ord_New[Qnt][7]=OrderMagicNumber(); // Магическое число
if (OrderComment()=="")
Mas_Ord_New[Qnt][8]=0; // Если нет коммент
else
Mas_Ord_New[Qnt][8]=1; // Если есть коммент
//------------------------------------------------------ 6 --
}
}
Mas_Ord_New[0][0]=Qnt; // Колич. ордеров
//--------------------------------------------------------------- 7 --
return;
}
//--------------------------------------------------------------- 8 --

В блоке 1-2 приводится комментарий описания глобальных массивов, используемых в функции. Глобальные массивы объявлены во включаемом файле Variables.mqh. В блоке 3-4 содержание массива Mas_Ord_New копируется в массив Mas_Ord_Old. Таким образом, ранее известное состояние ордеров запоминается и в дальнейшем может использоваться в программе. Далее значения элементов массивов Mas_Ord_New и Mas_Tip, отражающих новое состояние ордеров, обнуляется перед обновлением данных в блоке 4-7.

Блок 4-7 содержит цикл for, в котором последовательно опрашиваются все рыночные и отложенные ордера по финансовому инструменту, в окно которого прикреплён эксперт. Отбор ордеров производится с помощью функции OrderSelect() в соответствии с параметром MODE_TRADES, заданным по умолчанию. В блоке 5-6 вычисляются все необходимые характеристики для отобранных ордеров, и полученные значения заносятся в массив новых ордеров Mas_Ord_New. Одновременно производится подсчёт количества ордеров всех типов, и полученные значения присваиваются соответствующим элементам массива Mas_Tip. По окончании цикла общее количество ордеров по финансовому инструменту присваивается элементу Mas_Ord_New[0][0].

Отдельно нужно заметить, что анализ закрытых рыночных и удалённых отложенных ордеров (исполнение функции OrderSelect() с параметром MODE_HISTORY) не выполняется. Как правило, сведения о закрытых и удалённых ордерах в торгующих экспертах не используются. Сведения о закрытых и отложенных ордерах представляют историю по торговому счёту. Эти сведения могут быть использованы, например, для построения диаграмм, отражающих динамику вложения средств и фактических результатов торгов, однако не могут принести какую бы то ни было пользу для принятия новых торговых решений. Технически учёт этой части ордеров может быть выполнен аналогичным способом, однако, это - отдельная задача, которая не имеет отношения к торговле.

Анализ событий, связанных с ордерами, в программе выполняется на основе сравнения данных, имеющихся в рассмотренных массивах. Например, если массив Mas_Ord_Old содержит сведения о некотором отложенном ордере, номер которого 246810, а массив Mas_Ord_New содержит сведения о том же ордере 246810, но при этом ордер имеет уже другой тип, значит отложенный ордер был преобразован в рыночный. Анализ ордеров необходим также при осуществлении торговых операций (рассматривается в последующем изложении).

Перед самым первым исполнением функции Terminal() массивы Mas_Ord_Old и Mas_Ord_New пустые, т.е. каждый элемент обоих массивов имеет нулевое значение. Это значит, что после первого исполнения функции массив Mas_Ord_Old в строке

   ArrayCopy(Mas_Ord_Old, Mas_Ord_New);// Сохраняем предыдущую историю

наследует от массива Mas_Ord_New "нулевое" состояние, в результате чего при исполнении функции обработки событий могут появиться ложные сигналы о событиях. Для того чтобы этого не происходило, самое первое исполнение функции Terminal() осуществляется на этапе инициализации, и обработка событий после этого исполнения функции не производится (см. функцию init() в эксперте usualexpert.mq4).