Features of the mql5 language, subtleties and tricks - page 3

 
fxsaber:

What OnTradeTransaction can be in a trade script? Not in your code, but in someone else's trading script.
Do you seriously believe that a full-fledged trading robot can be written in a script?
 
Friends, let's please get closer to the subject: I would like to see examples of implementation of this or that statement. Not necessarily code, if there is a lot of it, you can describe the logic, for example, we send request to make sure it was sent, look there, if we get such-and-such a return code, we do so-and-such. That is, examples of the most reliable way to get data.

Otherwise, if we argue, we will move from useful topic to several pages of bickering. Then we will have to clean up everything to leave the essence... That's exactly what I would like to see the essence of this or that process. Let there be a few variants of some implementation of something. It will be possible to discuss advantages and disadvantages of each method.

Then, when enough different useful information is accumulated, there is an idea to accumulate it all into a table. And constantly replenish it with the accumulation of the next useful chips.
I think - it will be useful to all.
 
Question: how to convert a number to octal and hexadecimal.

Answers:
1.

Forum on trading, automated trading systems and trading strategies testing

8th and 16th Ritsa

Taras Slobodyanik, 2017.02.24 22:16

string DecToHex(int n)
  {
   string s = "", c;
   while(n != 0)
     {
      if(n%16<10)
         c=CharToStr(n%16+'0');
      else
         c=CharToStr(n%16+'A'-10);
      s = c + s;
      n = n / 16;
     }
   return(s);
  }
2.

Forum on trading, automated trading systems and testing trading strategies

8th and 16th Ritsa

Maxim Kuznetsov, 2017.02.24 22:20

Suddenly, StringFormat, PrintFormat :-)

PrintFormat("Hex %x and octal %o",1122,1122);
3.

Forum on trading, automated trading systems and testing trading strategies

8 and 16 ricas

fxsaber, 2017.02.24 22:21

string NumToString( uint Num, const uint Scale = 10 )
{
  static const string digits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
                                  "A", "B", "C", "D", "E", "F", "G", "H", "I", "K",
                                  "L", "M", "N", "O", "P", "Q", "R", "S", "T", "V", "X", "Y", "Z"};
  
  string Str = (Num == 0) ? "0" : "";
  
  while (Num > 0)
  {
    Str = digits[Num % Scale] + Str;
    
    Num /= Scale;
  }
  
  return(Str);
}

void OnStart()
{
  Print(NumToString(123, 8));
  Print(NumToString(123, 16));
}



 
prostotrader:
Do you seriously believe that a full-fledged trading robot can be written in a script?
You can
 
Alexey Kozitsyn:

If there will be discussions here, the branch will lose its practical importance. When they come to a real solution, they will write it here. And in my opinion, this should not be a branch of doubts or research. It should be a branch of practical solutions. And if several people have different visions of the issue, let them discuss it elsewhere.

<post to delete

Let's let the truth be found. I had time to think about it and decided to leave it, and Vitya (Vinin) whom I inquired and asked to dispel my doubts, also suggested to leave the discussion (confirming my doubts about the deletion) - let the truth be born. I think that would be more correct. I'm going to start tabulating it later anyway, so I can post it here as it fills up.
 
prostotrader:

You don't have to wait a few milliseconds.

The message will come in OnTradeTransaction

see code

What is the meaning of your message? Well it will come in OnTradeTransaction(), so what? This means that we have to wait for the event. We would have to wait anyway. The point of fxsaber's message is that after OrderSend() is executed the information about the executed action does not immediately appear in the terminal. Some people like to wait for OnTradeTransaction(), while others like to see an order or a deal in the list. For example, the difference from MT4. In M4, after OrderSend(), the order is already in the list of orders, and after OrderClose(), it is always in the history.

 
Artyom Trishkin:
Let's let us find the truth. I had time to think about it, so I decided to leave it, and Vitya (Vinin), whom I asked and asked to dispel my doubts, also suggested to leave the discussion (confirming my doubts about the deletion) - let the truth be born. I think that would be more correct. I'm going to start tabulating later anyway, to be posted here as it fills up.
The truth can not arise in arguments with prostotrader, he does not start them for that. As usual he doesn't even know what we're talking about.
 
What kind of argument is there? There is no dispute here. fxsaber reminded me of one feature of the terminal, which is really undocumented, and which everyone should really know, otherwise there will be problems when developing EAs, which you will have to find and clean up later.
 
Artyom Trishkin:
Let's let the truth be found...

Artem!

You are a reasonable and politically correct person!

What truth? You know exactly what we're talking about.

fxsaber wrote a script (not bad), but nobody praised it, so he

tries to remind about it in every thread.

Well done!

But here's the problem, you can't use OnTradeTransaction in this script, so I have to use "Mr. marbles" (like Sleep or another timer).

And of course, "caring" about other users who do not yet know that SCRIPT is better than COUNTER!

AndDmitry Fedoseev aproiore always against what I say, and it does not matter whether I am right or not.

You will never find the truth here, because it is not a CASE but a PERSONAL one that comes to the forefront.

 
class ORDERSEND  
{
private:
  static const bool IsTester;
  
  static bool Waiting( const bool FlagInit = false )
  {
    static ulong StartTime = 0;

    const bool Res = FlagInit ? false : (::GetMicrosecondCount() - StartTime < ORDERSEND::OrderSend_MaxPause);

    if (FlagInit)
      StartTime = ::GetMicrosecondCount();
    else if (Res)
      ::Sleep(0);

    return(Res);
  }

  static bool EqualPrices( const double Price1, const double Price2, const int digits)
  {
    return(::NormalizeDouble(Price1 - Price2, digits) == 0);
  }

  static bool HistoryDealSelect( MqlTradeResult &Result )
  {
    if ((Result.deal == 0) && (Result.order != 0))
    {
      if (::HistorySelectByPosition(::HistoryOrderGetInteger(Result.order, ORDER_POSITION_ID)))
        for (int i = ::HistoryDealsTotal() - 1; i >= 0; i--)
        {
          const ulong DealTicket = ::HistoryDealGetTicket(i);

          if (Result.order == ::HistoryDealGetInteger(DealTicket, DEAL_ORDER))
          {
            Result.deal = DealTicket;

            break;
          }
        }
    }

    return(::HistoryDealSelect(Result.deal));
  }

#define TMP_ORDERSEND_BENCHMARK(A) \
  static ulong Max##A = 0;         \
                                   \
  if (Interval##A > Max##A)        \
  {                                \
    ORDERSEND_BENCHMARK            \
                                   \
    Max##A = Interval##A;          \
  }

  static void OrderSend_Benchmark( const ulong Interval1, const ulong Interval2 = 0 )
  {
    #ifdef ORDERSEND_BENCHMARK
      TMP_ORDERSEND_BENCHMARK(1)
      TMP_ORDERSEND_BENCHMARK(2)
    #endif // ORDERSEND_BENCHMARK

    return;
  }

#undef TMP_ORDERSEND_BENCHMARK

#define WHILE(A) while ((!(Res = (A))) && ORDERSEND::Waiting())

public:
  static uint OrderSend_MaxPause; // максимальное время на синхронизацию в мкс.
  
  // Полностью синхронизированный с торговым окружением OrderSend.
  // По окончании работы ГАРАНТИРОВАННО и за МИНИМАЛЬНОЕ время доступно корректное торговое окружение.
  // По скорости ничем не уступает связке OrderSendAsync + OnTradeTransaction.
  // Учтены MT5-нюансы: Result.deal == 0, STATE_STARTED и STATE_MODIFY pending.
  // В тестере/оптимизаторе производительность равна штатной OrderSend.

  static bool OrderSendSync( const MqlTradeRequest &Request, MqlTradeResult &Result )
  {
    const ulong StartTime1 = ::GetMicrosecondCount();

    bool Res = ::OrderSend(Request, Result);

    const ulong Interval1 = ::GetMicrosecondCount() - StartTime1;

    const ulong StartTime2 = ::GetMicrosecondCount();

    if (Res && !ORDERSEND::IsTester && (Result.retcode < TRADE_RETCODE_ERROR) && (ORDERSEND::OrderSend_MaxPause > 0))
    {
      Res = (Result.retcode == TRADE_RETCODE_DONE);
      ORDERSEND::Waiting(true);

      if (Request.action == TRADE_ACTION_DEAL)
      {
        WHILE(::HistoryOrderSelect(Result.order))
          ;

        Res = Res && (((ENUM_ORDER_STATE)::HistoryOrderGetInteger(Result.order, ORDER_STATE) == ORDER_STATE_FILLED) ||
                      ((ENUM_ORDER_STATE)::HistoryOrderGetInteger(Result.order, ORDER_STATE) == ORDER_STATE_PARTIAL));

        if (Res)
          WHILE(ORDERSEND::HistoryDealSelect(Result))
            ;
      }
      else if (Request.action == TRADE_ACTION_PENDING)
      {
        if (Res)
          WHILE(::OrderSelect(Result.order) && ((ENUM_ORDER_STATE)::OrderGetInteger(ORDER_STATE) == ORDER_STATE_PLACED))
            ;
        else
        {
          WHILE(::HistoryOrderSelect(Result.order))
            ;

          Res = false;
        }
      }
      else if (Request.action == TRADE_ACTION_SLTP)
      {
        if (Res)
        {
          bool EqualSL = false;
          bool EqualTP = false;

          const int digits = (int)::SymbolInfoInteger(Request.symbol, SYMBOL_DIGITS);

          if ((Request.position == 0) ? ::PositionSelect(Request.symbol) : ::PositionSelectByTicket(Request.position))
          {
            EqualSL = ORDERSEND::EqualPrices(::PositionGetDouble(POSITION_SL), Request.sl, digits);
            EqualTP = ORDERSEND::EqualPrices(::PositionGetDouble(POSITION_TP), Request.tp, digits);
          }

          WHILE((EqualSL && EqualTP))
            if ((Request.position == 0) ? ::PositionSelect(Request.symbol) : ::PositionSelectByTicket(Request.position))
            {
              EqualSL = ORDERSEND::EqualPrices(::PositionGetDouble(POSITION_SL), Request.sl, digits);
              EqualTP = ORDERSEND::EqualPrices(::PositionGetDouble(POSITION_TP), Request.tp, digits);
            }
        }
      }
      else if (Request.action == TRADE_ACTION_MODIFY)
      {
        if (Res)
        {
          bool EqualSL = false;
          bool EqualTP = false;
          bool EqualPrice = false;

          const int digits = (int)::SymbolInfoInteger(Request.symbol, SYMBOL_DIGITS);

          if (::OrderSelect(Result.order))
          {
            EqualSL = ORDERSEND::EqualPrices(::OrderGetDouble(ORDER_SL), Request.sl, digits);
            EqualTP = ORDERSEND::EqualPrices(::OrderGetDouble(ORDER_TP), Request.tp, digits);
            EqualPrice = ORDERSEND::EqualPrices(::OrderGetDouble(ORDER_PRICE_OPEN), Request.price, digits);
          }

          WHILE((EqualSL && EqualTP && EqualPrice))
            if (::OrderSelect(Result.order) && ((ENUM_ORDER_STATE)::OrderGetInteger(ORDER_STATE) != ORDER_STATE_REQUEST_MODIFY))
            {
              EqualSL = ORDERSEND::EqualPrices(::OrderGetDouble(ORDER_SL), Request.sl, digits);
              EqualTP = ORDERSEND::EqualPrices(::OrderGetDouble(ORDER_TP), Request.tp, digits);
              EqualPrice = ORDERSEND::EqualPrices(::OrderGetDouble(ORDER_PRICE_OPEN), Request.price, digits);
            }
        }
      }
      else if (Request.action == TRADE_ACTION_REMOVE)
        if (Res)
          WHILE(::HistoryOrderSelect(Result.order))
            ;
    }

    const ulong Interval2 = ::GetMicrosecondCount() - StartTime2;

    Result.comment += " " + ::DoubleToString(Interval1 / 1000.0, 3) + " + " + ::DoubleToString(Interval2 / 1000.0, 3) + " ms";

    ORDERSEND::OrderSend_Benchmark(Interval1, Interval2);

    return(Res);
  }

#undef WHILE
};

static const bool ORDERSEND::IsTester = (::MQLInfoInteger(MQL_TESTER) || ::MQLInfoInteger(MQL_OPTIMIZATION) ||
                                         ::MQLInfoInteger(MQL_VISUAL_MODE) || ::MQLInfoInteger(MQL_FRAME_MODE));

static uint ORDERSEND::OrderSend_MaxPause = 1000000; // максимальное время на синхронизацию в мкс.

// Эта строчка позволяет сделать все OrderSend корректными.
#define OrderSend ORDERSEND::OrderSendSync

Everything is wrapped specifically in class to reduce the number of potential problems.

Using

OrderSend(Request, Result); // Все так же, как со штатной OrderSend

That is, to make all OrderSend synchronized with the trading environment and avoid the pitfalls, it is sufficient to write this source code as an mqh-file and make corresponding #include in your programs.