На рынке случаются различные эпизоды с исполнением торговых ордеров. Наверное, важно уметь быстро разобраться в той или иной торговой ситуации. MT5 сохраняет довольно много информации в истории торговли, нужно только суметь посмотреть на нее под правильным углом.
Ниже на нескольких примерах покажем, как найти интересные ситуации частичного исполнения и какие существуют способы их представления.
Этот скрипт находит события, когда один и тот же отложенный ордер создает несколько позиций, жизни которых не пересекаются. Т.е. сначала открылась и закрылась одна позиция, затем — вторая и т.д. И все они происходят из одного и того же отложенного ордера за счет его частичных исполнений на Hedge-счете.
#define MT4ORDERS_BYPASS_MAXTIME 1000000 // Максимальное время (в мкс.) на ожидание синхронизации торгового окружения #include <MT4Orders.mqh> // https://www.mql5.com/ru/code/16006 // Распечатывает MT4-записи с одним и тем же PositionID-идентификатором. void PrintPositionID( const ulong PositionID ) { const int Size = OrdersHistoryTotal(); for (int i = 0; i < Size; i++) if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) && (OrderTicketID() == PositionID)) OrderPrint(); return; } // Строковое представление сделки. string DealToString( const ulong &Ticket ) { const ENUM_DEAL_ENTRY EntryDeal = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(Ticket, DEAL_ENTRY); const int Digits = (int)SymbolInfoInteger(HistoryDealGetString(Ticket, DEAL_SYMBOL), SYMBOL_DIGITS); return((string)(datetime)HistoryDealGetInteger(Ticket, DEAL_TIME)) + " " + (string)Ticket + " " + ((EntryDeal == DEAL_ENTRY_IN) ? "+" : "-") + DoubleToString(HistoryDealGetDouble(Ticket, DEAL_VOLUME), 2) + " " + DoubleToString(HistoryDealGetDouble(Ticket, DEAL_PRICE), Digits) + " " + EnumToString(EntryDeal) + " " + (string)HistoryDealGetInteger(Ticket, DEAL_POSITION_ID); } // Строковое представление массива сделок (с одним PositionID-идентификатором). string DealsToString( const ulong &Deals[] ) { string Str = NULL; const int Size = ArraySize(Deals); double Lots = 0; int Amount = 0; for (int i = 0; i < Size; i++) { Lots += HistoryDealGetDouble(Deals[i], DEAL_VOLUME) * ((HistoryDealGetInteger(Deals[i], DEAL_ENTRY) == DEAL_ENTRY_IN) ? 1: -1); Str += DealToString(Deals[i]) + "_Lots = " + DoubleToString(Lots, 2) + ((MathAbs(Lots) < 1e-5) ? ": " + (string)(++Amount) : NULL) + "\n"; } return(Str); } void OnStart() { TRADESID TradesID; ulong PositionID[]; for (int i = TradesID.GetPositionsID(PositionID) - 1; i >= 0; i--) // Бежим по всем PositionID-идентификаторам. if (PositionID[i]) // Торговый идентификатор (не балансовые операции). { ulong Deals[]; double Lots = 0; // Суммарный лот порождаемых позиций. const int Size = TradesID.GetDealsByID(PositionID[i], Deals) - 1; // Получили все сделки с одинаковым PositionID-идентификаторам for (int j = 0; j < Size; j++) // Бежим по сделкам. { Lots += HistoryDealGetDouble(Deals[j], DEAL_VOLUME) * ((HistoryDealGetInteger(Deals[j], DEAL_ENTRY) == DEAL_ENTRY_IN) ? 1: -1); if (MathAbs(Lots) < 1e-5) // Если было порождено несколько позиций - распечатываем. { PrintPositionID(PositionID[i]); // В MT4-представлении. Print(DealsToString(Deals)); // Все сделки. break; } } } }
Рассмотрим некоторые результаты выполнения скрипта.
// MT4-представление. #2006402 2021.08.19 00:26:28.705 sell 0.03 USDJPY 109.790 0.000 109.781 2021.08.19 00:26:38.748 109.774 -0.056 -2.84 0.37 3;[0] 3 #2006466 2021.08.19 00:26:52.992 sell 0.17 USDJPY 109.790 0.000 109.782 2021.08.19 00:27:14.111 109.782 -0.32 0.00 1.06 3;[0];[0] 3 #2006474 2021.08.19 00:27:19.078 sell 0.03 USDJPY 109.790 0.000 109.782 2021.08.19 00:27:21.939 109.782 -0.06 0.00 0.19 3;[0];[0];[0];[0];[0];[0];[0] 3 #2006493 2021.08.19 00:27:24.011 sell 0.18 USDJPY 109.790 0.000 109.782 2021.08.19 00:27:45.709 109.782 -0.33 0.00 1.12 3;[0];[0];[0];[0];[0];[0];[0] 3 #2007698 2021.08.19 00:59:16.717 sell 0.26 USDJPY 109.798 0.000 109.790 2021.08.19 02:07:17.431 109.790 -0.44 0.00 1.62 3;[0];[0];[0];[0];[0];[0];[0] 3 // Все сделки. 2021.08.19 00:26:28 2006394 +0.03 109.790 DEAL_ENTRY_IN 3426935_Lots = 0.03 2021.08.19 00:26:38 2006402 -0.03 109.774 DEAL_ENTRY_OUT_BY 3426935_Lots = 0.00: 1 // Закрылась первая позиция (через CloseBy). 2021.08.19 00:26:52 2006418 +0.03 109.790 DEAL_ENTRY_IN 3426935_Lots = 0.03 2021.08.19 00:26:56 2006426 +0.03 109.790 DEAL_ENTRY_IN 3426935_Lots = 0.06 2021.08.19 00:27:00 2006431 +0.03 109.790 DEAL_ENTRY_IN 3426935_Lots = 0.09 2021.08.19 00:27:04 2006436 +0.03 109.790 DEAL_ENTRY_IN 3426935_Lots = 0.12 2021.08.19 00:27:09 2006439 +0.03 109.790 DEAL_ENTRY_IN 3426935_Lots = 0.15 2021.08.19 00:27:13 2006465 +0.02 109.790 DEAL_ENTRY_IN 3426935_Lots = 0.17 2021.08.19 00:27:14 2006466 -0.17 109.782 DEAL_ENTRY_OUT 3426935_Lots = -0.00: 2 // Закрылась вторая позиция. 2021.08.19 00:27:19 2006471 +0.03 109.790 DEAL_ENTRY_IN 3426935_Lots = 0.03 2021.08.19 00:27:21 2006474 -0.03 109.782 DEAL_ENTRY_OUT 3426935_Lots = -0.00: 3 // Закрылась третья позиция. 2021.08.19 00:27:24 2006476 +0.02 109.790 DEAL_ENTRY_IN 3426935_Lots = 0.02 2021.08.19 00:27:27 2006479 +0.02 109.790 DEAL_ENTRY_IN 3426935_Lots = 0.04 2021.08.19 00:27:30 2006482 +0.03 109.790 DEAL_ENTRY_IN 3426935_Lots = 0.07 2021.08.19 00:27:33 2006484 +0.03 109.790 DEAL_ENTRY_IN 3426935_Lots = 0.10 2021.08.19 00:27:36 2006486 +0.02 109.790 DEAL_ENTRY_IN 3426935_Lots = 0.12 2021.08.19 00:27:39 2006489 +0.03 109.790 DEAL_ENTRY_IN 3426935_Lots = 0.15 2021.08.19 00:27:42 2006491 +0.03 109.790 DEAL_ENTRY_IN 3426935_Lots = 0.18 2021.08.19 00:27:45 2006493 -0.18 109.782 DEAL_ENTRY_OUT 3426935_Lots = -0.00: 4 // Закрылась четвертая позиция. 2021.08.19 00:59:16 2006970 +0.26 109.798 DEAL_ENTRY_IN 3426935_Lots = 0.26 2021.08.19 02:07:17 2007698 -0.26 109.790 DEAL_ENTRY_OUT 3426935_Lots = 0.00: 5 // Закрылась пятая позиция.
По сделкам можно оценить, к чему приводят частичные исполнения, которых было множество. Видно, что были сформированы пять позиций.
Каждый раз писать подобные скрипты, чтобы разобраться в хронологии исполнения ордеров, неудобно. Однако, существуют готовые решения.
На скрине два представления рассматриваемой ситуации.
Верхний — штатная визуализация в виде одной строки, соответствующей всем исполнениям одного отложенного ордера (единый PositionID-идентификатор). Удобно, что одной строкой и встроено в GUI терминала. Но крайне скудно, не разобраться, что происходило.
Нижний (таблица) — это визуализация MT4-представления той же истории исполнения, но за счет нескольких иных сущностей: MT4-позиций, которые создает библиотека MT4Orders.
Хорошо видно, когда зарождались соответствующие позиции и каков их финансовый результат, включая другие подробности.
Таково различие MT5 и MT4-представлений торговой истории. Первый — лаконичный, второй — подробный.
// MT4-представление. #2429648 2021.11.16 23:58:39.093 sell 0.30 AUDCHF 0.67939 0.00000 0.67913 2021.11.16 23:58:42.309 0.67963 -0.964 0.00 -6.84 103;[0] 103 #2429915 2021.11.16 23:59:44.453 sell 0.50 AUDCHF 0.67939 0.00000 0.67910 2021.11.17 00:10:02.531 0.67901 -1.61 -3.48 18.05 103;[0];[0];[0] 103 #2429920 2021.11.16 23:59:44.453 sell 0.10 AUDCHF 0.67939 0.00000 0.67910 2021.11.17 00:10:03.693 0.67904 -0.32 -0.69 3.32 103;[0];[0];[0] 103 #2430627 2021.11.17 00:30:39.016 sell 0.29 AUDCHF 0.67928 0.00000 0.67906 2021.11.17 01:01:37.912 0.67906 -0.94 0.00 6.06 103;[0];[0];[0];[0];[0];[0];[0] 103 // Все сделки. 2021.11.16 23:58:39 2429630 +0.15 0.67939 DEAL_ENTRY_IN 5697587_Lots = 0.15 2021.11.16 23:58:42 2429647 +0.15 0.67939 DEAL_ENTRY_IN 5697587_Lots = 0.30 2021.11.16 23:58:42 2429648 -0.30 0.67963 DEAL_ENTRY_OUT_BY 5697587_Lots = 0.00: 1 // Закрылась первая позиция (через CloseBy). 2021.11.16 23:59:44 2429680 +0.15 0.67939 DEAL_ENTRY_IN 5697587_Lots = 0.15 2021.11.16 23:59:47 2429695 +0.15 0.67939 DEAL_ENTRY_IN 5697587_Lots = 0.30 2021.11.16 23:59:51 2429705 +0.15 0.67939 DEAL_ENTRY_IN 5697587_Lots = 0.45 2021.11.16 23:59:55 2429706 +0.15 0.67939 DEAL_ENTRY_IN 5697587_Lots = 0.60 2021.11.17 00:10:02 2429915 -0.50 0.67901 DEAL_ENTRY_OUT 5697587_Lots = 0.10 // Частичное закрытие второй позиции. 2021.11.17 00:10:03 2429920 -0.10 0.67904 DEAL_ENTRY_OUT 5697587_Lots = -0.00: 2 // Закрылась вторая позиция. 2021.11.17 00:30:39 2430264 +0.29 0.67928 DEAL_ENTRY_IN 5697587_Lots = 0.29 2021.11.17 01:01:37 2430627 -0.29 0.67906 DEAL_ENTRY_OUT 5697587_Lots = -0.00: 3 // Закрылась третья позиция.
Если бы мы сидели у терминала во время исполнения этого отложенного ордера, то видели бы, как последовательно были сформированы и закрыты три позиции, порожденные одним отложенным ордером за счет его частичных исполнений. Однако, внимательный наблюдатель увидел бы, что частичное исполнение происходило не только во время открытий позиций, но и на закрытии (см. в логе комментарий выше).
Мы снова видим, что MT5-предсталение максимально лаконично. Однако, MT4-представление имеет не три, а четыре позиции. Именно такой способ выбран для визуализации частичных закрытий позиций. В таблице четко показано, что было частичное исполнение TakeProfit-позиции (зеленая рамка), реджект оставшейся части и другие подробности.
На примере PartialFills продемонстрировано, что разные сущности MT4/MT5-позиций позволяют соответствующим образом видеть/оценивать хронологию торговых событий.
Сама концепция такого представления позиций является платформо-независимой и может быть реализована для многих торговых API и рынков.
Даже на приведенных примерах нельзя не заметить, что частичное исполнение может проходить очень мелкими лотами на FOREX-рынке. Происходит и на открытии и на закрытии позиций. Безусловно, важно правильно обрабатывать все эти события. И, наверное, MT4-представления истории (и текущего торгового состояния) дают более подготовленную основу для этого.
Вышеприведенный скрипт показал и другие сценарии PartialFills . Например, оставшаяся часть отложенного ордера была удалена и в MT4-представлении можно было видеть, как жизнь залитой части, так и неисполненного остатка.
Загромождать этим не стал пост. Благо каждый при желании может воспользоваться предложенным инструментарием на своем торговом счете и оценить исполнение именно своих ордеров.