Чем в mql4 заменить OnTradeTransaction()? - страница 8

 
Vitaly Muzichenko:

Всё, решение простое: вводим ещё одну проверку на изменение истории, таким образом ничего не пропадёт и отработает на 100%

Это даже можно использовать как неполноценный OnTrade()

void OnTrade()
 {
  ...
 }

static __OTotal = -1;
static __HTotal = -1;
int OT=OrdersTotal();
int HT=OrdersHistoryTotal();
  if(OT!=__OTotal || HT!=__HTotal) // если изменилось - выполняем
   {
     OnTrade(); // здесь дёргаем текущую ситуацию на счёте и заполняем структуры
     __OTotal=OrdersTotal(); // запомним текущее количество
     __HTotal=OrdersHistoryTotal(); // запомним количество в истории
   }
 
Vitaly Muzichenko:

Видать слаб умом)

Как это применить?

Проблема всего одна и она крайне редкая, сегодня её обнаружил впервые за пару лет, может и перед этим была, просто не замечал


Я говорил о подсчёте хэш-суммы - каким образом можно наименование символа добавить к ulong-значению хэш-суммы - посчитать значения кодов букв, входящих в состав наименования символа.

 
Vitaly Muzichenko:

Всё, решение простое: вводим ещё одну проверку на изменение истории, таким образом ничего не пропадёт и отработает на 100%

Вот выдержка из моей статьи №3:

-------

Остановимся подробнее на хэш-сумме в составе структуры.
Чтобы мы могли точно определить произошедшее изменение на счёте, нам недостаточно будет знать количество ордеров и позиций — отложенный ордер может быть удалён, и в этом случае изменится общее количество ордеров и позиций на счёте. Но... отложенный ордер может сработать и стать позицией. В этом случае общая сумма ордеров и позиций не изменится (для хэджевых счетов и MQL4) — количество позиций увеличилось, но количество ордеров уменьшилось, и в итоге общее количество осталось прежним. Это нам не подходит.

Рассмотрим тикет. Добавление/удаление отложенного ордера изменит общую сумму тикетов на счёте, срабатывание отложенного ордера не изменит общую сумму тикетов на счёте.

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

Значит смотрим ещё одно свойство позиции — время её изменения в милисекундах: открытие новой позиции изменит общее время изменения позиции, частичное закрытие изменит время изменения позиции, добавление объёма на неттинговом счёте изменит общее время изменения позиции.

Что из всего этого нам подойдёт для однозначного определения произошедшего изменения на счёте? Тикет+время изменения позиции. Проверим:

  • Открыли позицию — сумма тикетов изменилась + сумма времени изменения позиции изменилась есть изменение
  • Закрыли позицию — сумма тикетов изменилась + сумма времени изменения позиции изменилась есть изменение
  • Выставили отложенный ордер — сумма тикетов изменилась + сумма времени изменения позиции не измениласьесть изменение
  • Удалили отложенный ордер — сумма тикетов изменилась + сумма времени изменения позиции не изменилась есть изменение
  • Отложенный ордер активировался — сумма тикетов не изменилась + сумма времени изменения позиции изменилась есть изменение
  • Частичное закрытие позиции — сумма тикетов изменилась + сумма времени изменения позиции изменилась есть изменение
  • Добавление объёма к позиции — сумма тикетов не изменилась + сумма времени изменения позиции изменилась есть изменение
Таким образом, для хэш-суммы будем использовать тикет+время изменения позиции в милисекундах.

Тут я, правда, символ не добавлял к хэш-сумме - не было на то прецедентов. Но у меня работает совместно с проверкой истории. Посему - должно отрабатывать без ошибок. Впрочем, проверю как-нибудь.

Библиотека для простого и быстрого создания программ для MetaTrader (Часть III): Коллекция рыночных ордеров и позиций, поиск и фильтрация
Библиотека для простого и быстрого создания программ для MetaTrader (Часть III): Коллекция рыночных ордеров и позиций, поиск и фильтрация
  • www.mql5.com
В первой части данного цикла статей мы начали создавать большую кроссплатформенную библиотеку, целью которой является облегчение создания программ для платформы MetaTrader 5 и MetaTrader 4. Во второй части продолжили развитие библиотеки и сделали коллекцию исторических ордеров и сделок. В данной части повествования создадим класс для удобного...
 
Vitaly Muzichenko:

Всё, решение простое: вводим ещё одну проверку на изменение истории, таким образом ничего не пропадёт и отработает на 100%

А вот и да. Если не изменится количество открытых ордеров, то изменится количество в истории. (меня отложки не беспокоят - я их не пользую) И не надо лохматить бабушку перебирать ордера по чём зря весь день для отлавливания одного лишь события.

А если юзеру пришла СМСка в голову и он решил историю в терминале отразить вместо всей только за последний месяц, то просто выполнится лишняя проверка с перебором всех ордеров, что не смертельно ну вот ни разу.

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

 
Artyom Trishkin:

Вот выдержка из моей статьи №3:

-------

Остановимся подробнее на хэш-сумме в составе структуры.
Чтобы мы могли точно определить произошедшее изменение на счёте, нам недостаточно будет знать количество ордеров и позиций — отложенный ордер может быть удалён, и в этом случае изменится общее количество ордеров и позиций на счёте. Но... отложенный ордер может сработать и стать позицией. В этом случае общая сумма ордеров и позиций не изменится (для хэджевых счетов и MQL4) — количество позиций увеличилось, но количество ордеров уменьшилось, и в итоге общее количество осталось прежним. Это нам не подходит.

Рассмотрим тикет. Добавление/удаление отложенного ордера изменит общую сумму тикетов на счёте, срабатывание отложенного ордера не изменит общую сумму тикетов на счёте.

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

Значит смотрим ещё одно свойство позиции — время её изменения в милисекундах: открытие новой позиции изменит общее время изменения позиции, частичное закрытие изменит время изменения позиции, добавление объёма на неттинговом счёте изменит общее время изменения позиции.

Что из всего этого нам подойдёт для однозначного определения произошедшего изменения на счёте? Тикет+время изменения позиции. Проверим:

  • Открыли позицию — сумма тикетов изменилась + сумма времени изменения позиции изменилась есть изменение
  • Закрыли позицию — сумма тикетов изменилась + сумма времени изменения позиции изменилась есть изменение
  • Выставили отложенный ордер — сумма тикетов изменилась + сумма времени изменения позиции не измениласьесть изменение
  • Удалили отложенный ордер — сумма тикетов изменилась + сумма времени изменения позиции не изменилась есть изменение
  • Отложенный ордер активировался — сумма тикетов не изменилась + сумма времени изменения позиции изменилась есть изменение
  • Частичное закрытие позиции — сумма тикетов изменилась + сумма времени изменения позиции изменилась есть изменение
  • Добавление объёма к позиции — сумма тикетов не изменилась + сумма времени изменения позиции изменилась есть изменение
Таким образом, для хэш-суммы будем использовать тикет+время изменения позиции в милисекундах.

Тут я, правда, символ не добавлял к хэш-сумме - не было на то прецедентов. Но у меня работает совместно с проверкой истории. Посему - должно отрабатывать без ошибок. Впрочем, проверю как-нибудь.

Жирное решение, пока нет надобности для такого варианта.

Спасибо!

 
Vitaly Muzichenko:

Жирное решение, пока нет надобности для такого варианта.

Спасибо!

"Жирное" потому, что делалось не для локального решения, а как одна из частей полноценной замены OnTradeXXXX. Там в составе ещё работа с историей.

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

Но, повторюсь - библиотека делается для облегчения жизни тех, кому самому всё это делать очень долго и накладно. Ни на чём не настаиваю, естественно :)

 
Aleksandr Volotko:

А вот и да. Если не изменится количество открытых ордеров, то изменится количество в истории. (меня отложки не беспокоят - я их не пользую) И не надо лохматить бабушку перебирать ордера по чём зря весь день для отлавливания одного лишь события.

А если юзеру пришла СМСка в голову и он решил историю в терминале отразить вместо всей только за последний месяц, то просто выполнится лишняя проверка с перебором всех ордеров, что не смертельно ну вот ни разу.

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

Чтобы не перебирать весь день можно же проверку делать только когда соблюдены условия которые могут привести с изменению,открытию,закрытию позиции, т.е. ориентироваться на достижение тех цен, которые эксперт использует для открытия, ТП, СЛ. Ну да от логики эксперта зависит,  вам там виднее что дешевле.

 
Aleksey Mavrin:

Чтобы не перебирать весь день можно же проверку делать только когда соблюдены условия которые могут привести с изменению,открытию,закрытию позиции, т.е. ориентироваться на достижение тех цен, которые эксперт использует для открытия, ТП, СЛ. Ну да от логики эксперта зависит,  вам там виднее что дешевле.

Один советник (на одном компе, на одном континенте) торгует. Другой (на другом компе, на другом континенте) занимается своими функциями. Решение уже найдено.

 
fxsaber:

Буду благодарен, если предоставите какой-нибудь воспроизводимый пример (без опроса торговой истории).

Вот что получилось (хотя здесь оффтопик, но здесь просили).

Резал по живому. Без совместимости с MT4 (естественно), без обработки ошибок и т.д.

Торговля примитивная, открывает BUY, закрывает по SL/TP. Смысл только в демонстрации OnTradeTransaction() vs "опрос сервера".

У меня за указанный промежуток проход занял 2.34s vs 3.06s. Разница небольшая из-за малой нагрузки на серверные функции (только одна позиция, нет проверки магик и символа). В реальном эксперте разница будет много больше. Разница слегка будет нивелироваться за счёт расчёта сигналов и добавления трейлинга, но их необязательно делать на каждом тике. У меня ATR рассчитывается на M1, но за 6 часов (т.е. есть пространство для укрупнения TF). А трейлинг и безубыток рассчитывается на H3. Всё зависит от статегии.

// Test OnTradeTransaction.mqh
#property version   "1.00"
#property copyright "(c)2020 Edgar Akhmadeev"
#property link      "https://www.mql5.com/en/users/dali"
// 2020.01.27

//      Primitive expert to test OnTradeTransaction().
//      BUY only one position a time. There's no any signals.
//      Try OHLC M1 EURUSD 2016.12.19-2018.04.14 (bull trend) with default SL/TP.



//#define TESTER



#define MT4_TICKET_TYPE
#include <MT4Orders.mqh>
#include <mql4_to_mql5.mqh>



struct PosInfoBase {
        double                  price, sl, tp;
        datetime                time;
        int                     ticket;
        ENUM_ORDER_TYPE 	type;

        #ifndef TESTER
                int             mn;
                string          sym;
        #endif 
};

struct PosInfo {
        PosInfoBase             base;
        int                     ticket;
};



input int       SL              = 6;
input int       TP              = 900;



MqlTick         tick;
PosInfo         posInfo         = { 0 };



#ifdef TESTER

//*************************************************************************************************************
void 
OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) {
        if (trans.type == TRADE_TRANSACTION_ORDER_DELETE && trans.order_state == ORDER_STATE_PLACED) {
                // No money
                //errFatal = true;
                return;
        }
        
        static long lastTick;

        if (trans.type == TRADE_TRANSACTION_DEAL_ADD && trans.order_state == ORDER_STATE_STARTED) {
                // Open on market step1, SL/Order triggered step1, SL/Order triggered step4
                
                if (!HistoryDealSelect(trans.deal)) {
                        //errFatal = true;
                        return;
                }
                
                ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(trans.deal, DEAL_ENTRY);
                if (entry != DEAL_ENTRY_OUT)
                        return;
                
                ENUM_DEAL_REASON reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(trans.deal, DEAL_REASON);
                if (reason != DEAL_REASON_SL && reason != DEAL_REASON_TP)
                        return;
                
                if (lastTick == tick.time_msc)
                        return;

                posInfo.base.ticket = 0;
                InitPos();

                lastTick = tick.time_msc;
                return;
        }
}



#else // TESTER



//*************************************************************************************************************
bool
Support() {
        posInfo.base.ticket = 0;
        
        int cnt = PosTotal();
        if (cnt > 1)
                return false;
        
        PosInfo _posInfo;
        
        if (cnt == 0)
                _posInfo.base.ticket = 0;
        else {
                PosInfoFill(_posInfo);
                _posInfo.ticket = _posInfo.base.ticket;
        }

        //-------------------------------------------------------------------------------------------------------------
        // Position: process
        
        if (_posInfo.base.ticket != 0 && posInfo.ticket != 0 && _posInfo.base.ticket == posInfo.ticket) {
                // Ничего не произошло, та же позиция
                
                posInfo.base.ticket = _posInfo.base.ticket;
                posInfo.base.time = _posInfo.base.time;
                //posInfo.base.price = _posInfo.base.price;
                posInfo.base.sl = _posInfo.base.sl;
                posInfo.base.tp = _posInfo.base.tp;
        }

        //-------------------------------------------------------------------------------------------------------------
        // Инициализация новой позиции
        
        if (posInfo.base.ticket > 0)
                return true;
        
        return InitPos();
}

#endif // TESTER



//*************************************************************************************************************
bool
InitPos() {
        if (!SymbolInfoTick(_Symbol, tick))
                return false;
        
        posInfo.base.type = ORDER_TYPE_BUY;
        posInfo.base.sl = NormalizeDouble(tick.bid - SL * Point, Digits); 
        posInfo.base.tp = NormalizeDouble(tick.bid + TP * Point, Digits);       

        ResetLastError();
        int order = OrderSend(_Symbol, posInfo.base.type, 0.01, tick.ask, 99, posInfo.base.sl, posInfo.base.tp); 
        if (order < 0)
                return false;
        
        if (!OrderSelect(order, SELECT_BY_TICKET))
                return false;

        posInfo.base.price = OrderOpenPrice();
        posInfo.ticket = posInfo.base.ticket = order;
        posInfo.base.time = tick.time;
        return true;
}



//*************************************************************************************************************
int
PosTotal() {
        int posTotal = OrdersTotal();
        int cnt = 0;
        for (int i = posTotal - 1; i >= 0; --i) {
                if (!OrderSelect(i, SELECT_BY_POS)) {
                        //errFatal = true;
                        return -1;
                }

                if (OrderType() > OP_SELL)
                        continue;

                /*
                #ifndef TESTER
                        if (OrderMagicNumber() != MagicNum)
                                continue;
                        if (OrderSymbol() != symInfo.sym)
                                continue;
                #endif 
                */
                        
                ++cnt;
        } // for
        
        return cnt;
}


        
//*************************************************************************************************************
void
PosInfoFill(PosInfo& _posInfo) {
        ZeroMemory(_posInfo);

        _posInfo.base.ticket = (int)PositionGetInteger(POSITION_TICKET);
        _posInfo.base.type = (ENUM_ORDER_TYPE)PositionGetInteger(POSITION_TYPE);
        _posInfo.base.price = PositionGetDouble(POSITION_PRICE_OPEN);
        _posInfo.base.time = (datetime)PositionGetInteger(POSITION_TIME);
        _posInfo.base.sl = PositionGetDouble(POSITION_SL);
        _posInfo.base.tp = PositionGetDouble(POSITION_TP);

        #ifndef TESTER
                _posInfo.base.mn = (int)PositionGetInteger(POSITION_MAGIC);
                _posInfo.base.sym = PositionGetString(POSITION_SYMBOL);
        #endif 
}



//*************************************************************************************************************
void 
OnTick() {
        ResetLastError();
        if (!SymbolInfoTick(_Symbol, tick)) {
                int LE = GetLastError();
                //errFatal = true;
                return;
        }
        
        #ifdef TESTER

                if (posInfo.base.ticket > 0)
                        return;
                
                if (!InitPos()) {
                        //errFatal = true;
                        return;
                }

        #else  // TESTER
                
                if (!Support()) {
                        //errFatal = true;
                        return;
                }
        
        #endif // TESTER
}



//*************************************************************************************************************
int 
OnInit() {
        return INIT_SUCCEEDED;
}



//*************************************************************************************************************
void 
OnDeinit(const int reason) {
}
 
prostotrader:

Вы безнадежно отстали от жизни!

Давно эти события гарантированы!

Допустим, произошло событие в  OnTradeTransaction() после которого необходимо выполнить какие-то действия, но при первой попытке выполнить эти действия произошла ошибка. Что делать? Очевидно, надо повторить попытку, а для этого нужно где-то сохранить данные о необходимости повторения этих действий - скорее всего сохранение этих данных делается в обычных глобальных переменных советника или в статических функции. И вдруг пришлось перезапустить терминал... данные пропали. 

А когда анализируешь текущую ситуацию и историю - ничто никуда не улетает.

Причина обращения: