English Русский 中文 Español Deutsch Português
preview
リプレイシステムの開発(第33回):発注システム(II)

リプレイシステムの開発(第33回):発注システム(II)

MetaTrader 5 | 16 5月 2024, 16:37
60 0
Daniel Jose
Daniel Jose

はじめに

前回の「リプレイシステムの開発(第32回):受注システム(I)」稿では、EAで使用する発注システムの開発に着手しました。最初に本当に必要な関数だけを含む基本システムクラスを開発しました。

これらの関数は本質的に非常に基本的なものであり、発注システムを網羅することはできないと考える方もいらっしゃるかもしれません。その通りなのですが、この初期段階では、リプレイ/シミュレーションサービスで直接使用されることのないシステムを開発するつもりです。デモ口座でもリアル口座でも、実際の取引サーバーで動作するシステムを開発します。MetaTrader 5プラットフォームを幅広く活用し、当初から必要なサポートをすべて提供します。プラットフォームがサーバーと通信する最初の段階から、システムを完璧に動作させることが非常に重要です。なぜなら、リプレイ/シミュレーターしか使用しない場合、EAシステムをリプレイ/シミュレーターに適合させることができなくなるからです。再生/シミュレーターがEAの挙動と一致していることを確認しなければなりません。まず実際のサーバーでEAを実行する必要があるのはこのためです。

この要件は、システム内のメソッドと関数の数を減らすこと、つまりC_Ordersクラス内のメソッドと関数の数を減らすことにつながります。しかし、私たちは大きなシステムを作っていることを忘れてはなりません。C_Ordersクラスがすべてのニーズに応えられるわけではないと思うのは間違えです。MetaTrader 5プラットフォームが、取引サーバーとの連携に必要な最大限のサポートを提供してくれるようにするだけです。MetaTrader 5からの最大限のサポートの本質は、作成しなくてもよいものを作成しないようにすることです。車輪の再発明を試みるのではなく、リプレイ/シミュレーターシステムで作業する際に最小限の労力で済むよう、プラットフォームを最大限に利用すべきです。

発注システムを続ける前に、ある問題を解決する方法をお見せしたいと思います。ただし、これは問題というよりMetaTrader 5に存在する不便さです。


単純化を試みる

MetaTrader 5の常用ユーザーであれば、厄介でありながら、控えめに言ってもやる気を失わせるような点におそらくお気づきでしょう。私が言っているのは、他のプラットフォームからMetaTrader 5に乗り換えた方が、この操作に出会って苛立ったり、主にチャート分析に関わるいくつかの側面で、使いたくないと感じたりすることです。

問題は、資産チャート上で何らかの分析をおこなう際、分析に使用するグラフィカルオブジェクトを変更したり削除したりする際に困難が生じることがあるということです。MetaTrader 5の使い方を本当に知るには、その設定方法について知っておく必要があることがあります。読者がコンピュータにプラットフォームをインストールしたばかりで、一度も使用したことがないと仮定しましょう。つまり、これがプラットフォームとの最初の接触となります。1つ強調しておきたいことがあります。MetaTrader 5を初めて使用する方の話です。

ここで興味深い質問があります。古いオブジェクトをダブルクリックしても、選択を無効にするフラグ(チェックボックス、図01参照)がない限り、実際にオブジェクトにアクセスできます。

図01

図01:チェックボックスをアクティブにする

しかし、問題はそこではありません。問題は、他のプラットフォームから来た多くのユーザーが、オブジェクトだけをクリックすることに慣れていることです。こうしてオブジェクトが選択され、チャートの変更や削除が可能になります。MetaTrader 5がダブルクリックを要求することは完全には明らかではなく、このような場合にどのように進めるかを見つけるには時間がかかります。

では、詳細についてお話しましょう。MetaTrader 5では、この動作を変更することが可能です。設定にアクセスするには、CTRL + Oを押します。MetaTrader 5のオプションウィンドウが開きます。このウィンドウで、[チャート]タブを開き、[マウスのシングルクリックでオブジェクトを選択]を有効にします。そうすることで、MetaTrader 5でも他のプラットフォームと同様に選択を使用することができます。しかし、この場合であっても、この小さな調整では、まだいくつかの機能が欠けていることになります。私のここでの目的は、それを別の方法で、新たな可能性をもっておこなう方法を示すことです。

プログラマーとして、私はMetaTrader 5に乗り換えたユーザーがプラットフォームで作業する際にどうにか適切で快適な体験を得られるようにすることができる状況にいることに気づきました。そしてこれは、1回押すだけで済むように実装されます。しかし、ユーザーに十分なプログラミング経験がない場合、解決策はそれほど明白ではないかもしれません。また、そのような作業は必要ないと考える人もいるでしょうが、これは私たちの可能性を広げることになります。

この問題を解決するために、C_Terminalクラスに戻り、数行のコードを追加します。これだけで、新規ユーザーには十分な体験が提供できるでしょう。何が追加されるべきかを見てみましょう。以下のコードをご覧ください。

virtual void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
   {
      static string st_str = "";
                                
      switch (id)
      {
         case CHARTEVENT_CHART_CHANGE:
            m_Infos.Width  = (int)ChartGetInteger(m_Infos.ID, CHART_WIDTH_IN_PIXELS);
            m_Infos.Height = (int)ChartGetInteger(m_Infos.ID, CHART_HEIGHT_IN_PIXELS);
            break;
         case CHARTEVENT_OBJECT_CLICK:
            if (st_str != sparam) ObjectSetInteger(m_Infos.ID, st_str, OBJPROP_SELECTED, false);
            if (ObjectGetInteger(m_Infos.ID, sparam, OBJPROP_SELECTABLE) == true)
            ObjectSetInteger(m_Infos.ID, st_str = sparam, OBJPROP_SELECTED, true);
            break;
         case CHARTEVENT_OBJECT_CREATE:
            if (st_str != sparam) ObjectSetInteger(m_Infos.ID, st_str, OBJPROP_SELECTED, false);
            st_str = sparam;
            break;
      }
   }

このメソッドはすでにC_Terminalクラスの元のコードの一部ですが、2つの新しい出来事に関連する数行が追加されています。これらはMetaTrader 5プラットフォームからのものです。上のコードには1つ細かい点があります。しかし、まずはコードを説明し、それから詳細を説明することができます。静的なローカル変数を宣言し、検査対象のオブジェクトの名前を格納します。この変数は空文字列として初期化されます。すべてが正しくおこなわれることを望むのであれば、これは非常に重要なことです。チャート上のオブジェクトをクリックすると、その名前がプログラムに渡されます。また、プラットフォームはオブジェクト名を変数sparamに持つCHARTEVENT_OBJECT_CLICKイベントを渡します。このような些細なことが、次のステップに役立つのです。では、ローカル変数の名前が、MetaTrader 5から報告された名前と一致するかどうかを確認してみましょう。最初の実行の場合は異なります。 それらが同じであれば、何も起こりません。しかし、もし両者が異なっていれば、プラットフォームのフォーカスにあったオブジェクトがそのフォーカスになります。これは、オブジェクトを確認し、必要であればフォーカスを外す行でおこなわれます。

次の点に注意してください。オブジェクトのプロパティが図01のように変更された場合、ユーザーは意識的に「このオブジェクトは不用意に注目されるべきではない」と言っていることを理解しなければなりません。オブジェクトを変更すべきでないからか、オブジェクトが何かを指していて、その位置を変更したり、何かを変更したりしたくないからです。したがって、図01のようにチェックボックスをマークした場合、そのオブジェクトは無視されることを理解しなければなりません。この確認がまさにそうです。与えられたオブジェクトが無視されるべきかどうかを確認します。この確認がなければ、(図01のように)オブジェクトプロパティでユーザーがマークしたチェックボックスは無視され、オブジェクトにアクセスできてしまいます。したがって、このフォーカスを受け取るオブジェクトを作るには、次のコードを使用します。このコードでは、フォーカスを失ったときにプログラムがオブジェクトの名前を知っているように、オブジェクトの名前を保存していることに注目してください。MetaTrader 5がCHARTEVENT_OBJECT_CREATEイベントをトリガーすると、同様のことが起こります。しかし、ここで1つ細かいことがあります。CHARTEVENT_OBJECT_CLICKイベントとは異なり、このオブジェクト作成イベントは、オブジェクト作成について知りたいことをMetaTrader 5に伝えた場合にのみ、プログラムで発生します。

:いずれにせよ、MetaTrader 5は常にイベントをトリガーします。しかし、そのうちのいくつかは、私たちがプラットフォームに知らせた場合にのみ、私たちのコードに誘導されます。

MetaTrader 5に、チャート上にオブジェクトが作成されたときに通知を受けたいことを伝えるには、オブジェクトを削除する場合とほぼ同じ方法で進めます。次がコードです。

C_Terminal()
   {
      m_Infos.ID = ChartID();
      CurrentSymbol();
      m_Mem.Show_Descr = ChartGetInteger(m_Infos.ID, CHART_SHOW_OBJECT_DESCR);
      m_Mem.Show_Date  = ChartGetInteger(m_Infos.ID, CHART_SHOW_DATE_SCALE);
      ChartSetInteger(m_Infos.ID, CHART_SHOW_OBJECT_DESCR, false);
      ChartSetInteger(m_Infos.ID, CHART_EVENT_OBJECT_DELETE, 0, true);
      ChartSetInteger(m_Infos.ID, CHART_EVENT_OBJECT_CREATE, 0, true);
      ChartSetInteger(m_Infos.ID, CHART_SHOW_DATE_SCALE, false);
      m_Infos.nDigits = (int) SymbolInfoInteger(m_Infos.szSymbol, SYMBOL_DIGITS);
      m_Infos.Width   = (int)ChartGetInteger(m_Infos.ID, CHART_WIDTH_IN_PIXELS);
      m_Infos.Height  = (int)ChartGetInteger(m_Infos.ID, CHART_HEIGHT_IN_PIXELS);
      m_Infos.PointPerTick  = SymbolInfoDouble(m_Infos.szSymbol, SYMBOL_TRADE_TICK_SIZE);
      m_Infos.ValuePerPoint = SymbolInfoDouble(m_Infos.szSymbol, SYMBOL_TRADE_TICK_VALUE);
      m_Infos.VolumeMinimal = SymbolInfoDouble(m_Infos.szSymbol, SYMBOL_VOLUME_STEP);
      m_Infos.AdjustToTrade = m_Infos.ValuePerPoint / m_Infos.PointPerTick;
      m_Infos.ChartMode     = (ENUM_SYMBOL_CHART_MODE) SymbolInfoInteger(m_Infos.szSymbol, SYMBOL_CHART_MODE);
      ResetLastError();
   }

この行はMetaTrader 5に、今後、チャートに新しいオブジェクトが作成されたときに通知を受け取りたいことを伝えます。同様に、MetaTrader 5に通知を受け取らないように指示する必要があります。これは以下のコードでおこなわれます。

~C_Terminal()
   {
      ChartSetInteger(m_Infos.ID, CHART_SHOW_DATE_SCALE, m_Mem.Show_Date);
      ChartSetInteger(m_Infos.ID, CHART_SHOW_OBJECT_DESCR, m_Mem.Show_Descr);
      ChartSetInteger(m_Infos.ID, CHART_EVENT_OBJECT_DELETE, 0, false);
      ChartSetInteger(m_Infos.ID, CHART_EVENT_OBJECT_CREATE, 0, false);
   }

この行が実行されると、MetaTrader 5はオブジェクト作成イベントをコードに通知しなくなります。ユーザーがいつチャートにオブジェクトを追加または削除したかを知りたい場合があるため、このようなことは非常に重要であり、また興味深いことです。そして、これを手動で おこなおうとするのはかなり難しいですが、MetaTrader 5では非常に簡単です。プラットフォームが私たちの期待通りに動作するように操作できることにお気づきでしょう。このような行動、そして私たちにそれができるということは、新しいユーザーがこのプラットフォームを使用してより良い経験をする手助けができるということであり、非常にモチベーションが上がります。これはすべて適応の問題ですが、プログラマーとして「非プログラマー」を助けることができれば、適応はより早く進みます。

さて、この記事で実際に実装することになった内容に戻りましょう。まだやるべきことがたくさんあります。


発注システムの拡大

このトピックのタイトルは少々大げさかもしれませんが、別の連載記事で紹介したものを私たちの発注システムに持ち込みたいと思います。そこで得たのと同じ概念や知識を使用することができます。当連載の最新記事は、「自動で動くEAを作る(第15回):自動化(VII)」でご覧ください。この記事では、手動で構築管理されているEAを自動EAに変換する方法をテストしました。今このトピックを提起しているのは、リプレイ/シミュレーターでEAの動作を観察し、調整することに読者が興味があるかもしれないからです。EAの機能をテストするために、MetaTrader 5プラットフォームは、優れた仕事をするストラテジーテスターを提供していることを覚えておいてください。ここでは、テスターと並行して何かを作るのではありません。アイディアは、市場が閉まっているときでも、何らかのテクニックを実践できるようにすることです。

それでは、自動化EAの作成に関する連載で取り上げた概念とアイデアを紹介しましょう。まずはタイマークラスからです。

重要な注意事項:この最初のフェーズでは、EAを使用し、取引サーバーへのアクセスを容易にすることに重点を置いて開発するため、その連載からインポートする関数の概要を簡単に説明します。より詳細で掘り下げた説明については、この連載をお読みください。


C_ControlOfTimeによる時間の制御

C_ControlOfTimeは非常に興味深いクラスです。コードはかなりコンパクトであるにもかかわらず、かなりシンプルな方法で、取引可能な時間に基づいた一定レベルのコントロールが可能なEAを作ることができます。多くのトレーダーは最初の相場の動きを心配し、ポジションを早々にエントリしたり、エグジットしたりします。感情を必要としないところで感情に基づいて決断を下すことで、私たちはしばしば損失を被ります。もし計画に忠実であれば、その瞬間に取引することはなかったでしょう。このコントロールを有効にする最も簡単な方法の1つは、スケジュールを使用することです。連載「自動で動くEAを作る」では、そのようなスケジューラーの実装方法を紹介しました。では、新しいEAにインポートしてみましょう。同じ動作を作成します。これは非常に良いことです。市場で取引するのに適切で少し安全だと考えるタイムゾーン以外で取引する人は誰もいないからです。EAに協力してもらいます。

C_ControlOfTimeクラスはこのように始まります。

#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
#include "C_Orders.mqh"
//+------------------------------------------------------------------+
class C_ControlOfTime : protected C_Orders
{
   private :
      struct st_00
      {
         datetime Init,
                  End;
      }m_InfoCtrl[SATURDAY + 1];
//+------------------------------------------------------------------+

ここで変数に、操作に許される時間を格納します。おそらく、このコードで最も不思議なのは、SATURDAYの定義が使用されていることでしょう。連載「自動で動くEAを作る」を読んでいない方のために、この定義が何を意味するのかを簡単に説明します。この定義を用いることで、行列ですべての曜日をカバーすることを目指します。しかし、1つ重要なことがあります。これは、行列がZEROから始まるため、正しい長さを確保するために必要です。しかし、要素数がゼロの行列はありません。常にゼロより大きい値から始めるべきです。1を足したのはこのためです。こうしなければ、7要素ではなく6要素の行列になってしまいます。もう1つ、C_ControlOfTimeクラスがC_Ordersクラスを継承していることにお気づきでしょう。このように、C_Ordersクラスの機能を拡張します。しかし、この延長は、この後の説明でわかるように、実際にはEAには引き継がれません。その理由は、連載「自動で動くEAを作る」を読めばよくわかります。

次にクラスのコンストラクタです。そのコードは次のとおりです。

C_ControlOfTime(C_Terminal *arg, const ulong magic)
                :C_Orders(arg, magic)
   {
      for (ENUM_DAY_OF_WEEK c0 = SUNDAY; c0 <= SATURDAY; c0++) ZeroMemory(m_InfoCtrl[c0]);
   }

ここで、2つの簡単なことを理解する必要があります。1つ目は、C_ControlOfTimeコンストラクタのコードが実行される前に、C_Ordersクラスを初期化するということです。2つ目の、そしておそらくより不思議な特徴は、ループの存在です。面白いのはその操作方法です。このループでは、SUNDAYから始まる列挙を使用しており、変数はSATURDAYまで増加しています。これは可能でしょうか。はい、ただし、注意しなければなりません。主な懸念は、SUNDAYがSATURDAYよりも低い値を持つことです。そうでなければ、行列データへのアクセスに問題が生じます。幸いなことに、列挙はSUNDAYから始まり、SATURDAYまで日ごとに進むので、曜日がわかります。

このプログラミングモードを使用する主な利点は、コードのレベルが向上し、MQL5言語が自然言語に非常に近くなることです。このアプローチは、連載「自動で動くEAを作る」で使用され、詳しく説明されています。まあ、ここでお見せしたのはほんの2、3点です。これまでの記事を読めば、コードをさらに読みやすくする方法がわかるでしょう。この実践により、プログラミングの知識が十分でない人でもコードを理解できるようになります。覚えておいてください。マシンのためにプログラムするのではなく、他のプログラマーのためにプログラムするのです。

では、他の2つのメソッドを見てみましょう。

virtual void SetInfoCtrl(const ENUM_DAY_OF_WEEK index, const string szArg) final
   {
      string szRes[], sz1[];
      bool bLocal;
                                
      if (_LastError != ERR_SUCCESS) return;
      if ((index > SATURDAY) || (index < SUNDAY)) return;
      if (bLocal = (StringSplit(szArg, '-', szRes) == 2))
      {
         m_InfoCtrl[index].Init = (StringToTime(szRes[0]) % 86400);
         m_InfoCtrl[index].End = (StringToTime(szRes[1]) % 86400);
         bLocal = (m_InfoCtrl[index].Init <= m_InfoCtrl[index].End);
         for (char c0 = 0; (c0 <= 1) && (bLocal); c0++)
            if (bLocal = (StringSplit(szRes[0], ':', sz1) == 2))
               bLocal = (StringToInteger(sz1[0]) <= 23) && (StringToInteger(sz1[1]) <= 59);
         if (_LastError == ERR_WRONG_STRING_DATE) ResetLastError();
      }
      if ((_LastError != ERR_SUCCESS) || (!bLocal))
      {
         Print("Error in the declaration of the time of day: ", EnumToString(index));
         ExpertRemove();
      }
   }

この部分については、「自動で動くEAを作る(第10回):自動化(II)」稿で説明され議論されました。その仕組みについて詳しく説明しました。これに関してさらに詳細が必要な場合、あるいはコードを理解できない場合は、前述の記事を読んでください。次のメソッドも同じ記事に記載されています。実際、C_ControlOfTimeクラスに関連してここでおこなわれたすべての作業は、前述の記事で見ることができます。コンストラクタは唯一違います。私たちが次におこなうことのためです。

virtual const bool CtrlTimeIsPassed(void) final
   {
      datetime dt;
      MqlDateTime mdt;
                                
      TimeCurrent(mdt);
      dt = (mdt.hour * 3600) + (mdt.min * 60);
      return ((m_InfoCtrl[mdt.day_of_week].Init <= dt) && (m_InfoCtrl[mdt.day_of_week].End >= dt));
   }

この説明と、上記の記事を読んでいただければ、ユーザーがC_ControlOfTimeクラスを設定できるように、EAがいくつかの追加パラメータを取得することが理解できると思います。しかし、私たちはこの機能を新しいクラスに取り入れる必要があります。連載「自動で動くEAを作る」と同様に、ここでもプロキシクラスを使用します。これは次のセクションのテーマです。


C_Manager:管理クラス

C_Managerは、EAコードに関連する複雑さのほとんどをEA自体から切り離すことができるので、実際にはかなり興味深いクラスです。つまり、EAは数行のコードしか持たず、クラスがすべてを管理操作します。このコードは、連載「自動で動くEAを作る」で見たコードとは異なります。まずは基本的なことから始めましょう。主な問題は、EAが実際にはすべての状況で機能するわけではないということです。当初は、EAの運用を可能な限り安全にすることに重点を置きます。というのも、後でリプレイ/シミュレーターシステムでも動作させる必要があるからです。そして、これがこのシステムの最も難しい部分です。

物事が極端に複雑になるのを防ぐため、まずEAをMetaTrader 5プラットフォームで利用可能なもので動作するようにします。つまり、発注システムの幅はそれほど広くないということです。例えば、クロスオーダーモードでは使用できません。つまり、この初期段階では、発注システムを使用して、EAが動作している資産以外の資産の注文を送信することはできません。

それでは、C_Managerクラスの現在の開発状態のコードを見てみましょう。コードは次の行から始まります。

#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
#include "C_ControlOfTime.mqh"
#include "..\System EA\Auxiliar\Study\C_Study.mqh"
//+------------------------------------------------------------------+
#define def_Prefix "Manager"
#define def_LINE_PRICE  def_Prefix + "_PRICE"
#define def_LINE_TAKE   def_Prefix + "_TAKE"
#define def_LINE_STOP   def_Prefix + "_STOP"
//+------------------------------------------------------------------+
#define def_AcessTerminal       (*Terminal)
#define def_InfoTerminal        def_AcessTerminal.GetInfoTerminal()
#define def_AcessMouse          (*Study)
#define def_InfoMouse           def_AcessMouse.GetInfoMouse()
//+------------------------------------------------------------------+

ここでは、さらなるコーディングを容易にするために、いくつかの宣言を提供します。システムが非常に複雑であることから、これらの定義は将来的に変更される可能性が高いです。

クラスが始まるところを見てみましょう。これがそのコードです。

class C_Manager : public C_ControlOfTime
{
   private :
      struct st00
      {
         double  FinanceStop,
                 FinanceTake;
         uint    Leverage;
         bool    IsDayTrade,
                 AccountHedging;                                         
      }m_Infos;
      struct st01
      {
         color   corPrice,
                 corTake,
                 corStop;
         bool    bCreate;
      }m_Objects;             
//+------------------------------------------------------------------+
      C_Terminal *Terminal;
      C_Study    *Study;

ここでは、クラスのprivateグローバル変数を宣言します。よりよく整理するために、要素を構造体に分けました。このような構造体であれば、後でコードの一部を修正したり削除したりすることが容易になります。これは今後の記事で必ず起こることです。当面は、MetaTrader 5の機能を最大限に活用し、最もシンプルな形でシステムを動作させるようにします。繰り返しますが、このシステムを最終的なものと考えてはいけません。まだ開発段階です。

C_Managerクラスの最初の関数を見てみましょう。そのコードは以下の通りです。

bool CreateOrder(const ENUM_ORDER_TYPE type, const double Price)
   {
      ulong tmp;
                                
      if (!CtrlTimeIsPassed()) return false;
      tmp = C_Orders::CreateOrder(type, Price, m_Infos.FinanceStop, m_Infos.FinanceTake, m_Infos.Leverage, m_Infos.IsDayTrade);
                                
      return tmp > 0;
   }

この関数は、未決注文を取引サーバーに送信します。ただし、時間追跡システムが送信を許可した場合のみ、注文が送信されますのでご注意ください。スケジュールに従って取引時間を超えている場合、注文は送信されません。ここで必要なのは、注文を出す価格だけです。買いか売りかに関係なく、他のすべてはグローバルクラス変数に従って記入されます。

以下は、クラスのprivate関数です。

bool ToMarket(const ENUM_ORDER_TYPE type)
   {
      ulong tmp;
                                
      if (!CtrlTimeIsPassed()) return false;
      tmp = C_Orders::ToMarket(type, m_Infos.FinanceStop, m_Infos.FinanceTake, m_Infos.Leverage, m_Infos.IsDayTrade);
                                
      return tmp > 0;
   }

ここでは、市場価格(利用可能な最良の価格)での約定リクエストを送信します。この場合、必要なのは買うか売るかだけです。それ以外はすべて、グローバルクラス変数からの情報に基づいておこなわれます。これらのグローバル変数はEAのコードで初期化されるべきだと考えていらっしゃるかもしれません。違います。クラス内に存在するグローバル変数は、それが属するクラスに関する適切な注意と知識がない限り、どのような形であれアクセスすべきではありません。

そのような変数を初期化するためのリソースがいくつかあります。今のところ、最も単純なメソッドであるコンストラクタを使用することにします。コンストラクタを使用してクラス変数を初期化するのは、間違いなく最良の方法です。しかし、現実的な理由から、これは後で変更します。とりあえず、コンストラクタで必要なものを実装すればいいのです。そのコードは次のとおりです。

C_Manager(C_Terminal *arg1, C_Study *arg2, color cPrice, color cStop, color cTake, const ulong magic, const double FinanceStop, const double FinanceTake, uint Leverage, bool IsDayTrade)
          :C_ControlOfTime(arg1, magic)
   {
      string szInfo = "HEDGING";
                                
      Terminal = arg1;
      Study = arg2;
      if (CheckPointer(Terminal) == POINTER_INVALID) SetUserError(C_Terminal::ERR_PointerInvalid);
      if (CheckPointer(Study) == POINTER_INVALID) SetUserError(C_Terminal::ERR_PointerInvalid);
      if (_LastError != ERR_SUCCESS) return;
      m_Infos.FinanceStop     = FinanceStop;
      m_Infos.FinanceTake     = FinanceTake;
      m_Infos.Leverage        = Leverage;
      m_Infos.IsDayTrade      = IsDayTrade;
      m_Infos.AccountHedging  = false;
      m_Objects.corPrice      = cPrice;
      m_Objects.corStop       = cStop;
      m_Objects.corTake       = cTake;
      m_Objects.bCreate       = false;
      switch ((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE))
      {
         case ACCOUNT_MARGIN_MODE_RETAIL_HEDGING: m_Infos.AccountHedging = true; break;
         case ACCOUNT_MARGIN_MODE_RETAIL_NETTING: szInfo = "NETTING";            break;
         case ACCOUNT_MARGIN_MODE_EXCHANGE      : szInfo = "EXCHANGE";           break;
      }
      Print("Detected Account ", szInfo);
   }

このコードは長いように見えますが、クラス内に存在するすべてのグローバル変数を初期化することを考えれば、実際には非常にシンプルです。このすべての初期化は、実際にはEAコードによって提供されたパラメータに基づいておこなわれます。そこで、ここでシステムを初期化し、EAが動作する口座タイプを確認します。これは後で重要になります。現在は、口座タイプを理解するための分析情報を提供しているだけです。この情報は、この行で作成されたメッセージを使用して、MetaTrader 5プラットフォームのツールバーに提供されます。

デストラクタもあります。

~C_Manager()
   {
      ObjectsDeleteAll(def_InfoTerminal.ID, def_Prefix);
   }

このコードにはこの行が含まれていますが、ほとんど何もしません。すべてがスムーズにいくとは思っていませんので、何らかの問題が発生した場合、デストラクタはそのクラスが作成したオブジェクトを削除します。


結論

知識が再利用可能であることにお気づきでしょうか。いきなり何かを生み出すことはありません。私たちは常に物事を再利用し、改良しています。その結果、時間とともに向上していきます。ただし、C_Managerクラスにはまだ説明が必要なメソッドがあります。EAコード同様、現在の開発段階にあります。しかし、より適切な説明をするため、そして最も重要なことは、この記事が長くなり、読んで理解するのが面倒にならないようにするため、次回はこのメソッドとEAコードについての話に充てたいと思います。

コードの説明はまだ十分ではありません。十分な知識がないまま読者に使用してほしくないので、この記事にはコードは掲載しません。すみませんが、掲載するのが正しいとは思いません。


MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/11482

添付されたファイル |
Anexo.zip (130.63 KB)
リプレイシステムの開発(第34回):発注システム (III) リプレイシステムの開発(第34回):発注システム (III)
今回は、構築の第一段階を完成させます。この部分はかなり短時間で終わりますが、前回までに説明しなかった詳細をカバーします。多くの方が理解していない点をいくつか説明します。なぜShiftキーやCtrlキーを押さなければならないかご存じでしょうか。
母集団最適化アルゴリズム:微小人工免疫系(Micro-AIS) 母集団最適化アルゴリズム:微小人工免疫系(Micro-AIS)
この記事では、身体の免疫系の原理に基づいた最適化手法、つまりAISを改良した微小人工免疫系(Micro Artificial Immune System:Micro-AIS)について考察します。Micro-AISは、より単純な免疫系のモデルと単純な免疫情報処理操作を用います。また、この記事では、従来のAISと比較した場合のMicro-AISの利点と欠点についても触れています。
リプレイシステムの開発(第35回):調整(I) リプレイシステムの開発(第35回):調整(I)
前に進む前に、いくつかのことを解決する必要があります。これらは実際には必要な修正ではなく、クラスの管理方法や使用方法の改善です。その理由は、システム内の何らかの相互作用によって障害が発生したということです。このような失敗をなくすために原因を突き止めようと試みましたが、すべて失敗に終わりました。例えば、C/C++でポインタや再帰を使用すると、プログラムがクラッシュしてしまいます。
MQL5でマーケットメイク系アルゴリズムを作成する MQL5でマーケットメイク系アルゴリズムを作成する
マーケットメーカーはどのように機能するのでしょうか。この問題を考えて、原始的なマーケットメイク系アルゴリズムを作ってみましょう。