mql5言語の特徴、微妙なニュアンスとテクニック - ページ 3

 
fxsaber

トレーディングスクリプトにはどのようなOnTradeTransactionがあり得るか?自分のコードではなく、他人のトレーディングスクリプトで。
本格的なトレーディングロボットがスクリプトで書けると本気で思っているのでしょうか?
 
この文言の実装例を見てみたい。必ずしもコードでなくても、たくさんあれば、例えば、リクエストを送信して送信されたことを確認し、そこを見て、このような戻りコードがあれば、このようなことをする、というようなロジックを記述することができます。すなわち、最も確実にデータを取得する方法の例。

そうでないと、議論すると有益な話題から数ページにわたる口喧嘩に発展してしまうからです。そして、そのエッセンスを残すために、すべてをきれいにしなければならない...。まさに、このプロセス、このプロセスのエッセンスが欲しいのです。あるものの実装にいくつかのバージョンがあるとする。各方式のメリット、デメリットを議論することが可能になる。

そして、さまざまな有用な情報が十分に蓄積されたところで、それをすべてテーブルに集積するアイデアがあります。そして、次に有用なチップが溜まったら常に補充する。
皆さんのお役に立つと思います。
 
質問:8進数と16進数の変換方法について。

回答はこちら
1.

トレーディング、自動売買システム、トレーディング戦略のテストに関するフォーラム

8リカ、16リカ

タラス・スロボダニク さん 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リカ

マキシム・クズネツォフ, 2017.02.24 22:20

Suddenly, StringFormat, PrintFormat :-).

PrintFormat("16進数 %xと8進数 %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));
}



 
プロストトレーダー
本格的なトレーディングロボットがスクリプトで書けると本気で思っているのでしょうか?
することができます。
 
アレクセイ・コジツィン

同志であるfxsaberとprostotraderの議論は別スレッドに移してください、ここで議論があるとスレッドが実用的な意味を失います。本当の解決策を思いついたら、ここに掲載する。そして、私の考えでは、これは疑いや研究の枝葉の部分であってはならないのです。現実的な解決策を示す枝であるべきだ。そして、もし数人の人がその問題について異なるビジョンを持っているならば、別の場所で議論させればいいのです。

<削除する投稿

真実を明らかにしよう。考える時間があったので投稿することにしたのですが、私の疑問を払拭するために問い合わせてお願いしたVitya(Vinin)さんも、(削除に対する私の疑問を確認する)ディスカッションを投稿することを提案してくれました--真実を見抜こうではありませんか。それが正しいことだと思うんです。どうせ後で集計を始めるから、埋まったらここに載せればいいや。
 
プロストトレーダー

数ミリ秒を待つ必要はないのです。

メッセージはOnTradeTransactionで 表示されます。

コードを見る

メッセージのポイントは何ですか?OnTradeTransaction()で届くから何? イベントを待てばいいということです。とにかく待つのです。fxsaberのメッセージの意味は、OrderSend()を実行した後、実行されたアクションの情報がすぐにターミナルに表示されないということである。OnTradeTransaction()を待つのが好きな人もいれば、リストで注文や取引を確認するのが好きな人もいます。ここでは、例としてMT4との違いを紹介します。M4 では、OrderSend() の後、オーダーはすでにオーダーリストにあり、OrderClose() の後、オーダーは常に履歴に残ります。

 
アルチョム・トリシキン
真実を明らかにしよう。私は考える時間があったので、放置することにしたのですが、私の疑念を払拭するためにお願いしてお願いしたVitya(Vinin)も、(削除に対する私の疑念を確認して)議論から離れることを提案しました--真実が生まれるように。それが正しいことだと思うんです。とにかく後で集計を開始し、埋まり次第ここに掲載する予定です。
プロストレーダーとの議論では、真実は語られないかもしれませんが、それは彼が議論を始める理由ではありません。相変わらず自分が何を言っているのかすら分かっていない。
 
ところで、どんな議論があるのでしょうか?ここに争いはない。fxsaberは、ターミナルに本当に文書化されていない機能があり、誰もが本当に知っておく必要があることを思い出させてくれました。そうしないと、EAを開発する ときに問題が発生し、後でそれを見つけて解決する必要があります。
 
アルチョム・トリシキン
真実を明らかにしよう...。

アルチョム!

あなたは合理的で政治的に正しい人だ!

どんな真実?よくご存じですね。

fxsaberがスクリプトを書いたが(悪くはない)、誰も褒めてくれなかったので、彼は

は、すべてのスレッドでそれを思い出させようとします。

よくぞ言ってくれました。

しかし、ここで問題なのは、このスクリプトではOnTradeTransactionが使えないので、「OnTradeTransactionさん」から(スリープや他のタイマーなど)「ボールを転がす」必要があることだ。

そしてもちろん、SCRIPTがCOUNTERより優れていることをまだ知らない他のユーザーへの「気遣い」です!

ドミトリー・フェドセフは、私の言うことが正しくても間違っていても、いつも反対するんだ。

原因ではなく、個人的なものが前面に出てくるので、ここに真実は見いだせません。

 
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-fileとして記述し、対応する#includeをプログラムに使用すればよいのです。

理由: