Можно ли в коде изменить математический знак (только знак) по выбранному условию? - страница 3

 
Alexey Viktorov #:


Ну вот например для расчета тейкпрофита для Buy и Sell ордеров. Выбранный принцип один и тот же. Но в одном случае надо прибавлять, а в другом вычитать. А так код фактически одинаков.  Как тут что разделить на 2 части?
 
leon_17 #:
Ну вот например для расчета тейкпрофита для Buy и Sell ордеров. Выбранный принцип один и тот же. Но в одном случае надо прибавлять, а в другом вычитать. А так код фактически одинаков.  Как тут что разделить на 2 части?

На примере TrailingStop. Надо написать трейлинг для Buy и Sell.

bool TrailingSL_Sell( const int SL )
{
  MqlTick Tick;
  SymbolInfoTick(_Symbol, Tick);

  const double NewSL = Tick.ask - SL * _Point;

  return((OrderStopLoss() < NewSL) &&
         OrderModify(OrderTicket(),
                     OrderOpenPrice(),
                     NewSL,
                     OrderTakeProfit(),
                     OrderExpiration()));
}

bool TrailingSL_Buy( const int SL )
{
  MqlTick Tick;
  SymbolInfoTick(_Symbol, Tick);

  const double NewSL = Tick.bid + SL * _Point;

  return((OrderStopLoss() > NewSL) &&
         OrderModify(OrderTicket(),
                     OrderOpenPrice(),
                     NewSL,
                     OrderTakeProfit(),
                     OrderExpiration()));
}

Подсветкой показал, в каких местах отличия. Т.е. на 99% копипаста, делая которую, конечно, можно ошибиться. Очевидно, что в мире программирования давно в курсе подобных рисков, поэтому придуманы различные решения.


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

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Можно ли в коде изменить математический знак (только знак) по выбранному условию?

fxsaber, 2023.09.09 11:34

  • Макросы.
  • Шаблоны.
  • Указатели на функции.

Один из этих вариантов должен помочь, если правильно понял задачу.


У каждого есть свои плюсы и минусы. Вот так выглядит решение через макрос.

#define TRAILING(NAME, PRICE, OPER, SIGN)               \
  bool TrailingSL_##NAME( const int SL )                \
  {                                                     \
    MqlTick Tick;                                       \
    SymbolInfoTick(_Symbol, Tick);                      \
                                                        \
    const double NewSL = Tick.##PRICE OPER SL * _Point; \
                                                        \
    return((OrderStopLoss() SIGN NewSL) &&              \
           OrderModify(OrderTicket(),                   \
                       OrderOpenPrice(),                \
                       NewSL,                           \
                       OrderTakeProfit(),               \
                       OrderExpiration()));             \
  }


TRAILING(Sell, ask, -, <)
TRAILING(Buy, bid, +, >)

Для компилятора эта запись и самая верхняя идентичны.


Вы можете дальше использовать эти функции в классическом виде.

input int inSL = 100;

void OnTick()
{
  if (OrderType() == OP_BUY)
    TrailingSL_Buy(inSL);
  else if (OrderType() == OP_SELL)
    TrailingSL_Sell(inSL);  
}
 
fxsaber #:

На примере TrailingStop. Надо написать трейлинг для Buy и Sell.

Подсветкой показал, в каких местах отличия. Т.е. на 99% копипаста, делая которую, конечно, можно ошибиться. Очевидно, что в мире программирования давно в курсе подобных рисков, поэтому придуманы различные решения.


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


У каждого есть свои плюсы и минусы. Вот так выглядит решение через макрос.

Для компилятора эта запись и самая верхняя идентичны.


Вы можете дальше использовать эти функции в классическом виде.

Браво! Похоже то, что нужно. Осталось только понять что такое макрос в MQL, но благо пример привели, надеюсь разберусь. На макросах - это лучшее решение?
Большое спасибо за примеры! Причем и за тот, который наконец-то явно описал суть проблемы! )  

 
leon_17 #:

На макросах - это лучшее решение?

Это исключительно дело вкуса. Т.е. очень субъективно. Основной минус подобных конструкций - сложность при отладке. Сам активно использую, как и другие методы.

 

1. Макросы увеличивают вероятность ошибок в коде. Потому что при компиляции код макроса не проверяется. Короче, написать макрос и не сделать ошибку, сложнее, чем скопипастить функицю и изменить в ней пару знаков.

2. С макросом вот эта вот "передача" знака в "функцию" возможна только на стадии компиляции. 

 

Когда смотрю на эту запись, понимаю, что точно не ошибся логически, т.к. все параметры перевернутые. Но это опять же очень субъективно.

 
Ну да... с точки зрения отслеживания логики сложновато получается, а еще и код компилятором не проверяется. Но хоть что-то.
В остальных методах с указателями и шаблонами, такие же проблемы?
 
leon_17 #:

Ну вот например для расчета тейкпрофита для Buy и Sell ордеров. Выбранный принцип один и тот же. Но в одном случае надо прибавлять, а в другом вычитать. А так код фактически одинаков.  Как тут что разделить на 2 части?

Так это ещё проще чем макросы. Вот на примере ниже

bool TrailingSL( const int SL, ENUM_POSITION_TYPE type)
{
int k = type == POSITION_TYPE_BUY ? 1 : -1;
MqlTick Tick;
  SymbolInfoTick(_Symbol, Tick);
double price = type == POSITION_TYPE_BUY ? Tick.bid : Tick.ask;
  const double NewSL = price + SL*k * _Point;
// Дальше использование исполнение
}

Или без тернарного оператора, за одно условие типа позиции меняется цена и коэффициент.

 
leon_17 #:
В остальных методах с указателями и шаблонами, такие же проблемы?

Там иные подходы. Для каждой задачи свои решения.

 
typedef double (*Operation)( const double, const double );

double Add( const double a, const double b )
{
   return a + b;
}

double Sub( const double a, const double b )
{
   return a - b;
}

double Mul( const double a, const double b )
{
   return a * b;
}

double Div( const double a, const double b )
{
   return a / b;
}

// Сложная функция
void Function( Operation Op )
{
   double a = 10;
   double b = 20;
   
   double c = Op( a, b );
   double d = Op( b, c );
}


void OnStart()
{
   bool condition1 = true;
   bool condition2 = false;
   bool condition3 = false;
   bool condition4 = false;
   
   if( condition1 ){
      Function( Add );
   }
   else if( condition2 ){
      Function( Sub );
   }
   else if( condition3 ){
      Function( Mul );
   }
   else if( condition4 ){
      Function( Div );
   }
}
Причина обращения: