Автозаполнение Стоп лосс в новом ордере.

 

На форме Новый Ордер, в отложенном ордере, при вводе Цены и нажатии на клавишу Tab, я хочу, чтобы автозаполнялось значения поля Стоп Лосс так, что если стоп лосс сработает, у меня оставалось 50% депозита.

Да, я хочу, чтобы я мог менять (нечасто) сколько процентов депозита у меня останется, если стоп лосс сработает, но пока нет идей, где...

Документация по MQL5: Свойства ордеров / Константы, перечисления и структуры
Документация по MQL5: Свойства ордеров / Константы, перечисления и структуры
  • www.mql5.com
Приказы на проведение торговых операций оформляются ордерами. Каждый ордер имеет множество свойств для чтения, информацию по ним можно получать с...
 

В штатной форме МТ5 наверно мы не скоро дождемся опции установки SL/TP в процентах или деньгах. Поэтому только MQL5-программа нас спасет.

Вот код от ИИ, вставленный в сервис MQL5, без всякой проверки (!).

Мониторит все позиции по всем символам или опциональному списку инструментов.

// Общая функция для модификации стоп-лосса с проверкой "лучшей цены"
bool ModifySL(ulong ticket, double riskAmountMoney)
{
   // 1. Выбираем позицию
   if(!PositionSelectByTicket(ticket)) return false;
   
   string symbol    = PositionGetString(POSITION_SYMBOL);
   double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
   double currentSL = PositionGetDouble(POSITION_SL);
   double lot       = PositionGetDouble(POSITION_VOLUME);
   double tp        = PositionGetDouble(POSITION_TP);
   int    digits    = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
   double point     = SymbolInfoDouble(symbol, SYMBOL_POINT);
   ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

   // 2. Рассчитываем стоимость дистанции через OrderCalcProfit
   double testPoints = 100.0 * point;
   double testPrice  = (type == POSITION_TYPE_BUY) ? (openPrice - testPoints) : (openPrice + testPoints);
   double profitInMoney = 0;

   // Используем тип ордера, соответствующий типу позиции
   ENUM_ORDER_TYPE orderType = (type == POSITION_TYPE_BUY) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;

   if(!OrderCalcProfit(orderType, symbol, lot, openPrice, testPrice, profitInMoney)) return false;
   
   double lossForTestPoints = MathAbs(profitInMoney);
   if(lossForTestPoints <= 0) return false;

   // 3. Рассчитываем целевую цену стоп-лосса
   double finalDistance = (riskAmountMoney / lossForTestPoints) * testPoints;
   double newSL = (type == POSITION_TYPE_BUY) ? (openPrice - finalDistance) : (openPrice + finalDistance);
   newSL = NormalizeDouble(newSL, digits);

   // 4. ПРОВЕРКА: Нужно ли менять стоп-лосс?
   // Меняем, если СЛ не установлен (0) ИЛИ если новый СЛ "безопаснее" (ближе к цене или в плюсе)
   bool needModify = false;

   if(currentSL == 0) 
   {
      needModify = true; // Стопа нет — ставим
   }
   else 
   {
      if(type == POSITION_TYPE_BUY)
      {
         if(newSL > currentSL) needModify = true; // Для Buy новый стоп выше старого
      }
      else if(type == POSITION_TYPE_SELL)
      {
         if(newSL < currentSL || currentSL == 0) needModify = true; // Для Sell новый стоп ниже старого
      }
   }

   if(!needModify) return false; // Текущий стоп уже лучше или такой же

   // 5. Отправка запроса через чистое API
   MqlTradeRequest request = {};
   MqlTradeResult  result  = {};
   
   request.action   = TRADE_ACTION_SLTP;
   request.position = ticket;
   request.symbol   = symbol;
   request.sl       = newSL;
   request.tp       = tp;

   return OrderSend(request, result);
}

// Функции-обертки (без изменений)
bool SetSLByPercent(ulong ticket, double percent)
{
   double balance = AccountInfoDouble(ACCOUNT_BALANCE);
   return ModifySL(ticket, balance * (percent / 100.0));
}

bool SetSLByMoney(ulong ticket, double moneyAmount)
{
   return ModifySL(ticket, moneyAmount);
}
Файлы:
 
Stanislav Korotky #:
Вот код от ИИ, вставленный в сервис MQL5, без всякой проверки (!).

А вы точно автор учебника? Вас на взломали?😁

Stanislav Korotky #:
newSL = NormalizeDouble(newSL, digits);

Сомнительная нормализация.

Stanislav Korotky #:
      if(type == POSITION_TYPE_BUY)
      {
         if(newSL > currentSL) needModify = true; // Для Buy новый стоп выше старого
      }
      else if(type == POSITION_TYPE_SELL)
      {
         if(newSL < currentSL || currentSL == 0) needModify = true; // Для Sell новый стоп ниже старого
      }

Очень сомнительное сравнение цен.

 
Vladislav Boyko #:

А вы точно автор учебника? Вас на взломали?😁

Сомнительная нормализация.

Очень сомнительное сравнение цен.

Я ж написал - без проверки - с восклицательным знаком.

Дотошные могут заменить нормализацию цены на MathRound(price / tick) * tick, где tick = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE).

А проблем со сравнениями я не вижу - утоните, что не так. Там есть лишняя проверка на ноль, но она не играет роли.

 
Stanislav Korotky #:
А проблем со сравнениями я не вижу - утоните, что не так. Там есть лишняя проверка на ноль, но она не играет роли.

Я вот этим сравниваю. CCompare - старый код, который мигрировал с MQL4 и живет в отдельном файле.

В eps я передаю (tickSize / 2.0).

#define _greater(a, b, x) ((a) - (b) > x)
#define _less(a, b, x) _greater(b, a, x)
#define _greaterOrEqual(a, b, x) ((a) - (b) > -x)
#define _lessOrEqual(a, b, x) ((a) - (b) < x)

class CCompare
  {
public:
   static bool greater(double v1, double v2, double eps) { return _greater(v1, v2, eps);        }
   static bool less(double v1, double v2, double eps)    { return _less(v1, v2, eps);           }
   static bool goe(double v1, double v2, double eps)     { return _greaterOrEqual(v1, v2, eps); }
   static bool loe(double v1, double v2, double eps)     { return _lessOrEqual(v1, v2, eps);    }
  };

#undef _greater
#undef _less
#undef _greaterOrEqual
#undef _lessOrEqual
 
Stanislav Korotky #:
утоните, что не так

Я подозреваю, что если разница между ценами больше нуля и меньше половины tickSize, то могут возникнуть проблемы, когда tickSize > _Point. Но это не точно, я уже не помню. Поэтому я и написал "сомнительное сравнение", а не "неправильное сравнение".

[edit]

Примерно как-то так:

  • type: POSITION_TYPE_BUY
  • newSL (unnormalized): 1.106
  • currentSL: 1.105
  • tickSize: 0.005
  • _Digits: 3

Если нормализуете с помощью NormalizeDouble, то newSL должен получиться невалидным с точки зрения торгового сервера.

Если нормализуете с помощью tickSize, то newSL будет строго равен currentSL.

Это все навскидку, я не проверял и могу ошибаться.

 
Vladislav Boyko #:
#define _greater(a, b, x) ((a) - (b) > x)
#define _less(a, b, x) _greater(b, a, x)
#define _greaterOrEqual(a, b, x) ((a) - (b) > -x)
#define _lessOrEqual(a, b, x) ((a) - (b) < x)

Те макросы неидеальные, к стати. Там 2 разных макроса могут вернуть true для одних и тех-же аргументов, когда разница строго равна 'x' или что-то типа того (не помню точно). Но в реальности 'x' подбирается таким образом, чтобы разница не совпала с ним настрого, поэтому я поленился отлаживать макросы.

 
Vladislav Boyko #:

Примерно как-то так:

  • type: POSITION_TYPE_BUY
  • newSL (unnormalized): 1.106
  • currentSL: 1.105
  • tickSize: 0.005
  • _Digits: 3

Если нормализуете с помощью NormalizeDouble, то newSL должен получиться невалидным с точки зрения торгового сервера.

Если нормализуете с помощью tickSize, то newSL будет строго равен currentSL.

Это все навскидку, я не проверял и могу ошибаться.

По поводу замены NormalizeDouble - согласен - написал предложение выше. Тогда в коде сравнение делается уже для нормализованного newSL и проблем нет.

Прикладываю файл с изменениями.

Файлы:
 
Stanislav Korotky #:

По поводу замены NormalizeDouble - согласен - написал предложение выше. Тогда в коде сравнение делается уже для нормализованного newSL и проблем нет.

Прикладываю файл с изменениями.

Да, точно, спасибо. Если нормализовать с помощью tickSize перед сравнением, то использование логики, подобной CCompare, для сравнения, наверное, является избыточным.