Особенности языка mql5, тонкости и приёмы работы - страница 3

 
fxsaber:

Какой OnTradeTransaction может быть в торговом скрипте? Не в вашем коде, а в чьем-нибудь торговом скрипте.
Вы что, сёрьёзно полагаете, что полноценного торгового робота можно написать в скрипте?
 
Друзья, давайте пожалуйста ближе к теме: хотелось бы видеть примеры реализации того, или иного утверждения. Не обязательно кодом, если его много, то можно логику описать, например, отсылаем запрос, чтобы убедиться в том, что он отправлен, смотрим там-то, при получении такого-то кода возврата, делаем так-то. Т.е., примеры наиболее надёжного получения данных.

А то ж, если будем ругаться-препираться, то из полезной темы мы скатимся в несколько страниц препираний. Потом всё чистить, чтобы осталась суть... Вот именно хотелось бы, чтобы здесь отображалась именно суть того, или иного процесса. Пусть будут несколько вариантов какой-либо реализации чего-либо. Можно будет обсудить достоинства и недостатки каждого метода.

Потом, когда накопится достаточно разной полезной информации, есть мысль аккумулировать всё это в табличку. И постоянно её пополнять при накоплении очередных полезных фишек.
Думаю - полезно будет от этого всем.
 
Вопрос: как перевести число в восьмиричную и шеснадцатиричную системы.

Ответы:
1.

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

8 и 16 рица

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.

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

8 и 16 рица

Maxim Kuznetsov, 2017.02.24 22:20

внезапно, StringFormat, PrintFormat :-)

PrintFormat("Шестнадцатиричное %x и восьмиричное %o",1122,1122);
3.

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

8 и 16 рица

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:
Вы что, сёрьёзно полагаете, что полноценного торгового робота можно написать в скрипте?
Можно
 
Alexey Kozitsyn:

Перенесите обсуждение товарищей fxsaber и prostotrader в отдельную ветку, если тут будут дискуссии - ветка потеряет свою практическую значимость. Когда придут к реальному решению - напишут его сюда. И, я считаю, это не должна быть ветка сомнений или изысканий. Это должна быть ветка практических решений. А если у нескольких человек разные видения вопроса - пусть обсудят его в другом месте.

<пост для удаления> 

Давайте дадим найти истину. Время было обдумать, и решил всё же оставить, да и Витя (Vinin) у коего я поинтересовался и попросил развеять мои сомнения, тоже предложил оставить обсуждение (подтвердив мои сомнения в удалении) - пусть истина родится. Думаю, так правильней будет. Всё равно позже собираюсь начать в табличку собирать, чтобы её здесь прикладывать по мере её наполнения.
 
prostotrader:

Да не надо ждать несколько миллисекунд.

Сообщение придёт в OnTradeTransaction 

см. код 

А смысл вашего сообщения? Ну придет в OnTradeTransaction(), ну и что? Это значит что надо ждать события. Все равно ждать. Смысл сообщения fxsaber в что, что после выполнения OrderSend() информация о выполненном действия появляется в терминале не сразу. Кому то нравится ждать OnTradeTransaction(), кому-то появления ордера или сделка в списке. Для примера - отличие от МТ4. В М4, после OrderSend() ордер уже есть в списке ордеров, а после OrderClose() всегда есть в истории. 

 
Artyom Trishkin:
Давайте дадим найти истину. Время было обдумать, и решил всё же оставить, да и Витя (Vinin) у коего я поинтересовался и попросил развеять мои сомнения, тоже предложил оставить обсуждение (подтвердив мои сомнения в удалении) - пусть истина родится. Думаю, так правильней будет. Всё равно позже собираюсь начать в табличку собирать, чтобы её здесь прикладывать по мере её наполнения.
В спорах с prostotrader истины возникнуть не может, он их не для этого затевает. Как всегда он даже не въехал о чем разговор.
 
Вообще какой тут спор? Здесь нет спора.  fxsaber напомнил об одной особенности терминала, действительно недокументированной, и которую нужно действительно знать всем, иначе будут проблемы при разработке советников, которые придется потом искать и разгребать.
 
Artyom Trishkin:
Давайте дадим найти истину...

Артём!

Вы разумный и политкорректный человек!

Какую истину? Вы-то прекрасно понимаете о чём идёт речь.

fxsaber написал скрипт (неплохой), но никто его не похвалил, вот он и

пытается в каждой теме напомнить о нём.

Хвалю - молодец!

Но вот беда, в эгом скрипте нельзя использовать OnTradeTransaction, вот и приходится из "г-на шарики катать" (типа Sleep или другой таймер) 

Ну и естественно "забота" о других пользователях, которые ещё не знают, что СКРИПТ - лучше СОВЕТНИКА! 

А Dmitry Fedoseev апроиоре всегда против того, что я скажу и не важно прав я или нет.

Истину здесь не найти, потому что не ДЕЛО, а ЛИЧНОЕ выходит на передний план. 

 
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

Все завернуто специально в класс, чтобы уменьшить количество потенциальных проблем.

Применение

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

Т.е. для придания всем OrderSend синхронизированности с торговым окружением и обхода подводных камней достаточно приведенный исходник оформить в виде mqh-файла и в своих программах делать соответствующий #include.

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