Действительно удивительно для бесшовного преобразования кода mt4. Молодцы, что проделали такую тяжелую работу, и спасибо, что поделились, я очень ценю это.
// Список изменений:// 14.06.2017:// Add: Включена изначально заложенная реализация определения SL/TP закрытых позиций (закрытых через OrderClose).// Add: MagicNumber теперь имеет тип long - 8 байт (раньше был int - 4 байта).// Add: Если в OrderSend, OrderClose или OrderModify цветовой входной параметр (самый последний) задать равным INT_MAX, то будет сформирован// соответствующий торговый MT5-запрос (MT4ORDERS::LastTradeRequest), но отправлен он НЕ будет. Вместо этого будет проведена его MT5-проверка,// результат которой станет доступен в MT4ORDERS::LastTradeCheckResult.// В случае успешной проверки OrderModify и OrderClose вернут true, иначе - false.// OrderSend вернет 0 в случае успеха, иначе - -1.//// Если же соответствующий цветовой входной параметр задать раным INT_MIN, то ТОЛЬКО в случае успешной MT5-проверки сформированного// торгового запроса(как в случае с INT_MAX) он БУДЕТ отправлен.// Add: Добавлены асинхронные аналоги MQL4-торговым функциям: OrderSendAsync, OrderModifyAsync, OrderCloseAsync, OrderDeleteAsync.// Возвращают соответствующий Result.request_id в случае удачи, иначе - 0.
Если нужно понять, терминал сделал отказ на торговый приказ или сервер.
Реал. Использую MT4Orders, виртуальное окружение через Virtual, виртуал синхронизирую с реалом. Для этого на каждом тике прохожусь по открытым в реале ордерам несколько раз. Для этого на первом проходе формирую список интересующих ордеров, на остальных проходах уже работаю с этим списком.
Реал. Использую MT4Orders, виртуальное окружение через Virtual, виртуал синхронизирую с реалом. Для этого на каждом тике прохожусь по открытым в реале ордерам несколько раз. Для этого на первом проходе формирую список интересующих ордеров, на остальных проходах уже работаю с этим списком.
Раньше был такой код:
Практика показала, что так делать не стоит. Частично залитый лимитник породит 2 ордера с одинаковым тикетом, и на втором проходе будет печаль.
Это фича MT4Orders. Однако, SELECT_BY_TICKET - это небыстрый механизм в MT4/5 и виртуалке. Одна из причин - если не найдет среди живых, полезет в историю (MODE_TRADES-флаг - только указание приоритета, где сначала искать).
Сейчас перешёл на такой код
Дополнительно делается снапшот перед работой. Так будет работать корректно или может ещё что-то вылезти?
Здесь уже речь о дополнении от Virtual.mqh. Безусловно, снепшоты очень круто ускорят работу, если торгуется много символов/мэджиков.
Снепшот сводит работу с внешним для советника окружением (торговый API) к минимуму. Т.е. самые тормозные функции вызываются единожды для изначального считывания, а далее вся работа с торговым окружением идет внутри советника незаметно для программиста, т.к. все тот же MT4-style.
Имеет смысл использовать один из этих вариантов снепшота.
#define VIRTUAL_SNAPSHOT_REFRESHTIME 1000// Время жизни снепшота для обновления. В MT5 требует подключенной MT4Orders.mqh#define VIRTUAL_SNAPSHOT_WITHOUT_HISTORY // Отказ от снепшота истории для повышения производительности#include <fxsaber\Virtual\Virtual.mqh>
VIRTUAL::Snapshot(); // 1: один (_Symbol) символ, все мэджики.
VIRTUAL::Snapshot(VIRTUAL_SNAPSHOT_REFRESHTIME, MyMagic); // 2: один (_Symbol), один мэджик.
VIRTUAL::Snapshot(VIRTUAL_SNAPSHOT_REFRESHTIME, -1, false, ""); // 3: все символы и мэджики.
Использую его. У меня в моновалютном советнике может быть несколько подТС (каждая со своим мэджиком). И даже если несколько советников на одном символе, все равно вижу для себя целесообразным использовать именно этот вариант. Т.е. один раз заснепшотил, а дальше все подТС работают с результатом.
Если моновалютный советник работает только с одним мэджиком, то самый быстрый вариант.
Мультивалютный советник, где можно задать мэджик или все мэджики.
Можно тысячу раз подряд вызвать VIRTUAL::Snapshot(), но он не будет взаимодействать с внешним торговым API чаще, чем задано в VIRTUAL_SNAPSHOT_REFRESHTIME (в примере это одна миллисекунда - мне хватает). Поэтому ничего не требуется запоминать, код, грубо говоря, становится таким.
VIRTUAL::Snapshot();
for (uint i = OrdersTotal(); (bool)i--;)
{
VIRTUAL::Snapshot();
do_something();
}
Вот мой код синхронизации (вызывается для каждой подТС) с виртуальными окружениями.
// Синхронизирует VirtualPointerTo-окружение на основе текущего (выбранного) и VirtualPointerOut (для закрытия позиций).staticbool SyncChannel( conststring &Symb, const MAGIC_TYPE Magic, constdouble Lots,
const VIRTUAL_POINTER &VirtualPointerTo, const VIRTUAL_POINTER &VirtualPointerOut, constint FlagChange = false )
{
// Нужно для механизма IsNull.if (!VirtualPointerTo.GetHandle() || !VIRTUAL::GetHandle())
_B2(VIRTUAL::Snapshot());
constbool IsNull = !OrdersTotal() && !_VP(VirtualPointerTo, OrdersTotal());
bool Res = IsNull || !FlagChange || _B(SYNCCHANNEL::IsNotChange(true), 500);
if (!IsNull)
{
Res &= SYNCCHANNEL::IsCloseBy(/*Symb*/) && MACRO_ISCHANGE(SYNCCHANNEL::SyncCloseBy(Symb, Magic, VirtualPointerTo/*, (inMinLotCorrection <= 0)*/));
Res &= MACRO_ISCHANGE(SYNCCHANNEL::SyncExistOrders(Symb, Magic, VirtualPointerTo, VirtualPointerOut));
if (Lots && (inMinLotCorrection > Lots))
::Alert("inMinLotCorrection(" + (string)inMinLotCorrection + ") > Lots(" + (string)Lots + ")");
Res &= MACRO_ISCHANGE(SYNCCHANNEL::SetNewLimit(Symb, Magic, Lots, OP_BUYLIMIT, VirtualPointerTo, inMinLotCorrection));
Res &= MACRO_ISCHANGE(SYNCCHANNEL::SetNewLimit(Symb, Magic, Lots, OP_SELLLIMIT, VirtualPointerTo, inMinLotCorrection));
}
return(Res);
}
Из выделенного видно создание снепшота. Его следует вызывать после тормозных функций. Например, OrderSend. Если лишний раз вызвать - ничего страшного, как показал в коде выше.
Однако, исходник привел по другой причине. Все потенциально тормозные функции при синхронизации облачаю в макрос, который полностью останавливает синхронизацию, если во время нее пришел новый тик (SymbolInfoTick или CopyTicks), т.к. требуется сначала новые тики пробросить через все виртуалки, а только потом синхронизировать с реалом. Все точно также, как должно работать у торговых копиров и на внешних крипто-биржах.
Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий
Библиотеки: MT4Orders
fxsaber, 2023.07.07 13:12
Производительность.
Таблица производительности (время выполнения в миллисекундах) для b3815 и b2958.
Везде использовалась MT4Orders от 20.07.2022.
По той же методике сравнительная таблица двух билдов MT5: b4040 и b4057.
На b4057+ производительность MT4Orders при работе с историей не уступает нативному MQL5.
Соответственно, больше (для MT5 b4057+) неактуальна данная ранее рекомендация.
Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий
Библиотеки: MT4Orders
fxsaber, 2023.07.07 13:12
Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий
Библиотеки: MT4Orders
fxsaber, 2017.06.14 11:30
Если нужно понять, терминал сделал отказ на торговый приказ или сервер.
Реал. Использую MT4Orders, виртуальное окружение через Virtual, виртуал синхронизирую с реалом. Для этого на каждом тике прохожусь по открытым в реале ордерам несколько раз. Для этого на первом проходе формирую список интересующих ордеров, на остальных проходах уже работаю с этим списком.
Раньше был такой код:
Практика показала, что так делать не стоит. Частично залитый лимитник породит 2 ордера с одинаковым тикетом, и на втором проходе будет печаль.
Сейчас перешёл на такой код
Дополнительно делается снапшот перед работой. Так будет работать корректно или может ещё что-то вылезти?
Реал. Использую MT4Orders, виртуальное окружение через Virtual, виртуал синхронизирую с реалом. Для этого на каждом тике прохожусь по открытым в реале ордерам несколько раз. Для этого на первом проходе формирую список интересующих ордеров, на остальных проходах уже работаю с этим списком.
Раньше был такой код:
Практика показала, что так делать не стоит. Частично залитый лимитник породит 2 ордера с одинаковым тикетом, и на втором проходе будет печаль.
Печали не будет, если делать так.
AddToArray(OrderTickets, (OrderType() <= OP_SELL) ? OrderTicket() : -OrderTicket());Это фича MT4Orders. Однако, SELECT_BY_TICKET - это небыстрый механизм в MT4/5 и виртуалке. Одна из причин - если не найдет среди живых, полезет в историю (MODE_TRADES-флаг - только указание приоритета, где сначала искать).
Сейчас перешёл на такой код
Дополнительно делается снапшот перед работой. Так будет работать корректно или может ещё что-то вылезти?
Здесь уже речь о дополнении от Virtual.mqh. Безусловно, снепшоты очень круто ускорят работу, если торгуется много символов/мэджиков.
Снепшот сводит работу с внешним для советника окружением (торговый API) к минимуму. Т.е. самые тормозные функции вызываются единожды для изначального считывания, а далее вся работа с торговым окружением идет внутри советника незаметно для программиста, т.к. все тот же MT4-style.
Имеет смысл использовать один из этих вариантов снепшота.
Можно тысячу раз подряд вызвать VIRTUAL::Snapshot(), но он не будет взаимодействать с внешним торговым API чаще, чем задано в VIRTUAL_SNAPSHOT_REFRESHTIME (в примере это одна миллисекунда - мне хватает). Поэтому ничего не требуется запоминать, код, грубо говоря, становится таким.
Вот мой код синхронизации (вызывается для каждой подТС) с виртуальными окружениями.
Из выделенного видно создание снепшота. Его следует вызывать после тормозных функций. Например, OrderSend. Если лишний раз вызвать - ничего страшного, как показал в коде выше.
Однако, исходник привел по другой причине. Все потенциально тормозные функции при синхронизации облачаю в макрос, который полностью останавливает синхронизацию, если во время нее пришел новый тик (SymbolInfoTick или CopyTicks), т.к. требуется сначала новые тики пробросить через все виртуалки, а только потом синхронизировать с реалом. Все точно также, как должно работать у торговых копиров и на внешних крипто-биржах.
Словил OrderBug22 В чем может бить проблема? RP 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) Line = 1537 NF 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) Before MT4ORDERS::HistoryDealSelect(Result): DP 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) MT4ORDERS::OrderSendBug = 22 CL 0 19:00:01.733 Pip Funnels 1.0 (AUDJPY,H2) Result.deal = 0
Нет проблемы.
какой-то баг
какой-то баг
Это норма.