MQL5で3Dモデリング

Sergey Pavlov | 27 2月, 2017

金融相場の時系列の立体表現をするために、例として3Dモデリングを使用できます。時系列は動的なシステムであり、連続確率変数の値が(タイマー刻み、バー、フラクタルなど) 等間隔で受信されます。この記事では、時系列とインジケーター の3次元化を検討します。(図1を参照)

図1。時系列の立体表現の例。

図1。時系列の立体表現の例。

2次元と3次元モデルの差は、特別な関数を使用して、平面上に 3 D モデルの幾何学的投影があるかどうかということです。平面上の3次元画像を作成するために次の手順が必要です。

  • モデリング-時系列での3次元モデルを作成します。
  • レンダリング (可視化)-選択したモデルに基づき投影します。
  • 結果のイメージを画面に表示します。

この記事の目的は、3次元空間で普通のチャートを示すことです。現在 MQL5では、3Dモデリング ソリューションを提供していません。したがって、3Dオブジェクトや座標系を含む方法を原理的に考えます。多くの読者はこのトピックについて懐疑的に感じるかもしれません。したがって、テキストざっと読んでしまうかもしれませんが、しかし、この記事から得られるアルゴリズムは、他のタスクで役に立ちます。


インタラクティブなチャートオブジェクト

3Dオブジェクトを始めます。MQL5の関数は、2次元のオブジェクトで動作し、複雑なグラフィカルな表現を作成することができます。関数を追加すると、3次元グラフィックスはMT5 ターミナルで利用可能になります。

まず、満たすべき要件は、3Dオブジェクトの基本クラスの設計です。

  1. 使いやすさ。
  2. 高持続性。
  3. 独立性
  4. インタラクティブ機能

使いやすさ。

使用者と開発者のために最小限の関数をセットを作成する必要がありますが、3次元グラフィックスのほとんどのことができるようにしなくてはなりません。

高持続性。

3Dオブジェクトは、クラスのインスタンスを作成したプログラムにおいて、永続的でなければなりません。偶発的または意図的な削除、その基本的なプロパティの変更に対して保護する必要があります。

独立性

オブジェクトは、"スマート"に変化し (座標系の回転)、基本的なアンカー ポイント等の変更状況を自動調整することができます。オブジェクトは正しく情報を処理、発生するイベントに応答する必要があります。

インタラクティブ機能

3D可視化には、ポイントを変更する関数が含まれます (座標系の回転) 。したがって、そのような追加コントロール パネルの必要性を排除する関数を作成する必要があります。厳密に言えば、MQL5言語内のグラフィカルオブジェクトには既に双方向のプロパティがあります。オブジェクトを選択、移動、プロパティなどを変更できます。このプロパティを少し向上させる必要があります。たとえば、座標の中心を変更した場合すべての関連オブジェクトは自動的に再配置される必要があります。

3Dオブジェクトはインタラクティブなグラフィカルオブジェクト (IGO)になります。インタラクティブなグラフィカルオブジェクトは、MQL5をグラフィカルオブジェクトに接続する必要があります。まず、インタラクティブなグラフィカルオブジェクトのCIGO基本クラスをから始めましょう。

class CIGO
  {
protected:
   bool              on_event;      //イベント フラグを処理
   int               m_layer;       //IGOが属しているレイヤー
   //---
   double            SetPrice(double def,int prop_modifier=0);
public:
   string            m_name;        //IGOオブジェクトの名前
   double            m_price;       //IGOの基本的なアンカー ポイント
   double            m_angle;       //IGOのスナップ角度 [deg]
                     CIGO();
                    ~CIGO();
   //---
   virtual     //メソッド:IGO作成
   void              Create(string name) {on_event=true;}
   virtual     //メソッド: IGOの描写
   void              Redraw() {ChartRedraw();}
   virtual     //処理メソッド OnChartEvent
   bool              OnEvent(const int id,         //イベント ID
                             const long &lparam,   //Long 型のイベント パラメータ
                             const double &dparam, //Double 型のイベント パラメータ
                             const string &sparam, //文字列型のイベント パラメータ
                             int iparamemr=0,      //IGOのイベント識別子
                             double dparametr=0.0);//Double 型のIGOイベント パラメータ
  };

基本クラスには、フィールドとメソッドをさらにオーバーライドまたは子クラスで補完することができる最小値があります。OnChartEventを処理するための仮想メソッドOnEvent()と基本的なアンカーを設定するためのメソッドポイントSetPrice()を考慮します。インタラクティブなグラフィカルオブジェクトの主な原則は、クラスで実装されます。

メソッド: 受信のOnEventイベントの処理。

このメソッドは、チャートを操作するときに、クライアントターミナルから受信したイベントを処理します。4つの標準的なイベントに応答するメソッド: グラフィカルオブジェクトを移動、クリックするとチャートのサイズ、プロパティを変更する、グラフィカルオブジェクトを削除します。イベントの詳細について考えてみましょう。

  1. グラフィカルオブジェクトを削除します。このイベントが発生すると、オブジェクトはチャートに存在せず、削除されています。しかし、永続性の要件であり、したがってオブジェクトをすぐに復元する必要があります。すなわちオブジェクトが削除の前にあった同じプロパティで再作成する必要があります。注:グラフィカルオブジェクトがここで削除され、CIGOクラスの関連付けられているインスタンスではありません。クラス インスタンスが削除されたグラフィカルオブジェクトに関する情報を格納します。よって、Create()メソッドを使用してこのオブジェクトを復元できます。
  2. チャートのサイズやプロパティを変更。新しいバー、チャート スケール、時間フレーム スイッチ、およびその他の変更など、多くのイベントがあります。このようなイベントへの応答はRedraw()メソッドを使用して、更新された環境に応じたオブジェクトの再描画する必要があります。別の時間枠に切り替えたとき、クラスインスタンスが再初期化され、チャートにグラフィカルオブジェクトがまだ存在していた場合でも、クラスのフィールドに格納されていた作成されたグラフィカルオブジェクトに関するデータを失うことに注意してください。したがって、インスタンスのフィールドを使用してグラフィカルオブジェクトのプロパティは復元されます。これはIGOの永続性を高めます。
  3. グラフィカルオブジェクトを移動グラフィカルオブジェクトの双方向性は、このプロパティに基づいています。オブジェクトを移動すると、その基本的なアンカー ポイントが変更されます。オブジェクトを移動する前に、 (ダブルクリック) で選択する必要があります。イベントが発生した場合、メソッドは true、それ以外の場合は false が返されます。この値はインタラクティブなグラフィカルオブジェクトの集合操作を整理するときに必要になります。移動できないグラフィカルオブジェクトが必要な場合、オブジェクトを作成するときに無効にする必要があります。
  4. グラフィカルオブジェクトをクリックオブジェクトに対してマウスが押された場合、オブジェクトが誤って移動することを防ぐ必要があります。したがって、1 つだけIGOオブジェクトを選択できます。
    boolCIGO::OnEvent (const int id
                       const long &lparam,
                       const double &dparam,
                       const string &sparam,
                       int iparamemr=0,
                       double dparametr=0.0)
      {
       bool res=false;
       if(on_event) //イベント処理が許可される
         {
          //グラフィカルオブジェクトを削除する
          if((ENUM_CHART_EVENT)id==CHARTEVENT_OBJECT_DELETE && sparam==m_name)
            {
             Create(m_name);
            }
          //チャートのサイズを変更またはハート プロパティ プロパティ] ダイアログ ボックスを使用してを変更する
          if((ENUM_CHART_EVENT)id==CHARTEVENT_CHART_CHANGE)
            {
             Redraw();
            }
          //グラフィカルオブジェクトを移動する
          if((ENUM_CHART_EVENT)id==CHARTEVENT_OBJECT_DRAG)
             if(ObjectGetInteger(0,sparam,OBJPROP_SELECTED)==1 && sparam==m_name)
               {
                m_price=ObjectGetDouble(0,m_name,OBJPROP_PRICE);
                Redraw();
                res=true;   //基本アンカー ポイントが変更されたことを知らせる
               }
          //このグラフィカルオブジェクトの外側をクリック
          if((ENUM_CHART_EVENT)id==CHARTEVENT_OBJECT_CLICK && sparam!=m_name)
            {
             ObjectSetInteger(0,m_name,OBJPROP_SELECTED,0);
             ChartRedraw();
            }
         }
       return(res);
      }

Parameters: 

 id

   [in]イベント id このメソッドを使用して処理できるイベントには 9 種類あります。

 lparam

   [in]Long 型のイベント パラメータ。

 dparam

   [in]Double 型のイベント パラメータ。

 sparam

   [in]文字列型のイベント パラメータ。

 iparametr

   [in]カスタム イベントの識別子です。

 dparametr

   [in]Long 型のカスタム イベントのパラメータ。

戻り値:

オブジェクトの基本的なアンカー ポイントの座標が変更された場合は true を返します。それ以外の場合は false を返します。 

 

メソッド: 基本的なアンカー ポイントSetPriceの座標を設定します。

クラス インスタンスのm_priceフィールドの「チャート」の座標システムの「価格」の値を設定します。

基本的なアンカー ポイントの座標がこのメソッドによってリクエストされたときに何が起こるかを説明しましょう。

  1. クラス インスタンスの初期化中に、m_priceフィールド (基本的なポイント座標) を任意のエントリー値に含まないためm_price=NULLとなります。クラスのインスタンスが作成されたとき、またはチャートの時間枠を切り替えたとき、初期化が実行されます。グラフィカルオブジェクトは、チャートに存在する可能性があります。前のプログラム呼び出し後、またはタイムフレームの切り替え後、チャートに存在する可能性があります。よって、グラフィカルオブジェクトの対応するプロパティの値はm_priceフィールドに割り当てられます。
  2. m_nameグラフィカルオブジェクトが存在しない場合、基本アンカー ポイントの座標が最初のステップの後定義されていない: >m_price=NULL。この場合m_priceフィールドは、 def既定値に設定されます。
double CIGO::SetPrice(double def,int prop_modifier=0)
  {
   if(m_price==NULL)             //変数の値がない場合
      m_price=ObjectGetDouble(0,m_name,OBJPROP_PRICE,prop_modifier);
   if(m_price==NULL)             //座標がない場合
      m_price=def;               //デフォルト値
   return(m_price);
  }

Parameters:

 def

   [in]変数の既定値。

 prop_modifier

   [in]グラフィカルオブジェクトのリクエストされたプロパティの修飾子。

戻り値:

 基本的なアンカー ポイントの座標の値。  

インタラクティブオブジェクトの基本クラスの子クラスを見てください。まず3次元モデリングに必要な環境を作成します。

 

C_OBJ_ARROW_RIGHT_PRICE クラス:「右の価格ラベル」オブジェクト

CIGO基本クラスから派生します。 

//+------------------------------------------------------------------+
//| Class OBJ_ARROW_RIGHT_PRICE: object "Right Price Label"          |
//+------------------------------------------------------------------+
class C_OBJ_ARROW_RIGHT_PRICE:public CIGO
  {
public:
   virtual     //メソッド: オブジェクトを作成する
   void              Create(string name);
   virtual     //メソッド: 描画オブジェクト
   void              Redraw();
  };
//+------------------------------------------------------------------+
//メソッド: オブジェクトを作成する |
//+------------------------------------------------------------------+
void C_OBJ_ARROW_RIGHT_PRICE::Create(string name)
  {
   m_name=name;
   m_price=SetPrice((ChartGetDouble(0,CHART_PRICE_MAX)+ChartGetDouble(0,CHART_PRICE_MIN))/2);
   ObjectCreate(0,m_name,OBJ_ARROW_RIGHT_PRICE,0,0,0);
   ObjectSetInteger(0,m_name,OBJPROP_SELECTABLE,true);
   ObjectSetInteger(0,m_name,OBJPROP_WIDTH,1);
   ObjectSetInteger(0,m_name,OBJPROP_COLOR,clrISO);
//---
   ObjectSetInteger(0,m_name,OBJPROP_TIME,0,T(0));
   ObjectSetDouble(0,m_name,OBJPROP_PRICE,0,m_price);
//---
   ChartRedraw();
   on_event=true; //イベント処理を許可する
  }
//+------------------------------------------------------------------+
//メソッド: オブジェクトの再描画 |
//+------------------------------------------------------------------+
void C_OBJ_ARROW_RIGHT_PRICE::Redraw()
  {
   ObjectSetInteger(0,m_name,OBJPROP_TIME,0,T(0));
   ChartRedraw();
  }

3次元座標系の中心を整理するためクラスに最適です。クラスのインスタンスは、現在のバー、Z軸にリンクされています。 

 

クラス C_OBJ_TREND:「トレンドライン」オブジェクト 

CIGO基本クラスから派生します。

//+------------------------------------------------------------------+
//| Class OBJ_TREND: the "Trendline" object                          |
//+------------------------------------------------------------------+
class C_OBJ_TREND:public CIGO
  {
public:
   virtual     //メソッド: オブジェクトを作成する
   void              Create(string name);
   virtual     //メソッド: 描画オブジェクト
   void              Redraw();
  };
//+------------------------------------------------------------------+
//メソッド: オブジェクトを作成する |
//+------------------------------------------------------------------+
void C_OBJ_TREND::Create(string name)
  {
   m_name=name;
   m_price=(ChartGetDouble(0,CHART_PRICE_MAX)+ChartGetDouble(0,CHART_PRICE_MIN))/2;
   ObjectCreate(0,m_name,OBJ_TREND,0,0,0);
   ObjectSetInteger(0,m_name,OBJPROP_COLOR,clrISO);
   ObjectSetInteger(0,m_name,OBJPROP_WIDTH,0);
   ObjectSetInteger(0,m_name,OBJPROP_STYLE,styleISO);
   ObjectSetDouble(0,m_name,OBJPROP_PRICE,0,m_price);
   ObjectSetInteger(0,m_name,OBJPROP_TIME,0,T(0));
   ObjectSetDouble(0,m_name,OBJPROP_PRICE,1,m_price+1);
   ObjectSetInteger(0,m_name,OBJPROP_TIME,1,T(0));
   ObjectSetInteger(0,m_name,OBJPROP_RAY_RIGHT,true);
   ObjectSetInteger(0,m_name,OBJPROP_RAY_LEFT,true);
   ObjectSetInteger(0,m_name,OBJPROP_BACK,true);
   ObjectSetInteger(0,m_name,OBJPROP_SELECTABLE,false);
//---
   ChartRedraw();
   on_event=true; //イベント処理を許可する
  }
//+------------------------------------------------------------------+
//メソッド: オブジェクトの再描画 |
//+------------------------------------------------------------------+
void C_OBJ_TREND::Redraw()
  {
   ObjectSetInteger(0,m_name,OBJPROP_TIME,0,T(0));
   ObjectSetInteger(0,m_name,OBJPROP_TIME,1,T(0));
   ChartRedraw();
  }

このクラスを使用して Z 軸を作成します。このクラスの最小値を出力しますが、3D モデリングの目的には十分です。

 

近似曲線の角度による「オブジェクトのクラス C_OBJ_TRENDBYANGLE: 

CIGO基本クラスから派生します。

//+------------------------------------------------------------------+
//クラス OBJ_TRENDBYANGLE:「近似曲線の角度によるオブジェクト |
//+------------------------------------------------------------------+
class C_OBJ_TRENDBYANGLE:public CIGO
  {
protected:
   int               m_bar;   //第2基本的なポイントをリンクする番号のバー
   //---
   double SetAngle(double def)
     {
      if(m_angle==NULL) //変数の値がない場合
         m_angle=ObjectGetDouble(0,m_name,OBJPROP_ANGLE);
      if(m_angle==NULL)       //座標がない場合
         m_angle=def;         //デフォルト値
      return(m_angle);
     }
public:
                     C_OBJ_TRENDBYANGLE();
   virtual     //メソッド: オブジェクトを作成する
   void              Create(string name,double price,double angle);
   virtual     //メソッド: 描画オブジェクト
   void              Redraw();
   virtual     //処理メソッド OnChartEvent
   bool              OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam,
                             int iparamemr=0,
                             double dparametr=0.0);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
C_OBJ_TRENDBYANGLE::C_OBJ_TRENDBYANGLE()
  {
   m_bar=c_bar;
  }
//+------------------------------------------------------------------+
//メソッド: オブジェクトを作成する |
//+------------------------------------------------------------------+
void C_OBJ_TRENDBYANGLE::Create(string name,double price,double angle)
  {
   datetime time=T(0);
   datetime deltaT=T(m_bar)-time;
   m_name=name;
   m_price=SetPrice(price);
   m_angle=SetAngle(angle);
   ObjectCreate(0,m_name,OBJ_TRENDBYANGLE,0,time,m_price,time+deltaT,m_price);
   ObjectSetInteger(0,m_name,OBJPROP_COLOR,clrISO);
   ObjectSetInteger(0,m_name,OBJPROP_WIDTH,0);
   ObjectSetInteger(0,m_name,OBJPROP_STYLE,styleISO);
   ObjectSetInteger(0,m_name,OBJPROP_RAY_RIGHT,true);
   ObjectSetInteger(0,m_name,OBJPROP_RAY_LEFT,true);
   ObjectSetInteger(0,m_name,OBJPROP_BACK,true);
   ObjectSetInteger(0,m_name,OBJPROP_SELECTABLE,true);
//---変化するトレンド ラインのトレンド。
//---ラインのポイントが新しい角度に従って自動的に決定されます
   ObjectSetDouble(0,m_name,OBJPROP_ANGLE,m_angle);
   ChartRedraw();
//---
   on_event=true; //イベント処理を許可する
  }
//+------------------------------------------------------------------+
//メソッド: オブジェクトの再描画 |
//+------------------------------------------------------------------+
void C_OBJ_TRENDBYANGLE::Redraw()
  {
   ObjectSetInteger(0,m_name,OBJPROP_TIME,T(0));
   ObjectSetInteger(0,m_name,OBJPROP_TIME,1,T(0)+T(m_bar)-T(0));
   ObjectSetDouble(0,m_name,OBJPROP_PRICE,m_price);
   ObjectSetDouble(0,m_name,OBJPROP_ANGLE,m_angle);
   ChartRedraw();
  }
//+------------------------------------------------------------------+
//処理メソッド OnChartEvent |
//+------------------------------------------------------------------+
boolC_OBJ_TRENDBYANGLE::OnEvent (const int id
                                 const long &lparam,
                                 const double &dparam,
                                 const string &sparam,
                                 int iparamemr=0,
                                 double dparametr=0.0)
  {
//---
   bool res=false;
   if(on_event) //イベント処理を許可
     {
      //グラフィカルオブジェクトを削除する
      if((ENUM_CHART_EVENT)id==CHARTEVENT_OBJECT_DELETE && sparam==m_name)
        {
         Create(m_name,m_price,m_angle);
        }
      //グラフィカルオブジェクトを削除する
      if((ENUM_CHART_EVENT)id==CHARTEVENT_CHART_CHANGE)
        {
         Redraw();
        }
      //グラフィカルオブジェクトを移動する
      if((ENUM_CHART_EVENT)id==CHARTEVENT_OBJECT_DRAG)
        {
         //---
         if(ObjectGetInteger(0,sparam,OBJPROP_SELECTED)==1 && sparam==m_name)
           {
            m_angle=ObjectGetDouble(0,m_name,OBJPROP_ANGLE);
            Create(m_name,m_price,m_angle);
            res=true;   //基本的なアンカー ポイントが変更されたことを知らせる
           }
         if(iparamemr==Event_1)//基本ポイントの変更についてのメッセージ
           {
            m_price=dparametr;
            Create(m_name,m_price,m_angle);
           }
         if(iparamemr==Event_2)//受信した角度の変更についてのメッセージ
           {
            m_angle=dparametr;
            Create(m_name,m_price,m_angle);
           }
        }
      //このグラフィカルオブジェクトの外側をクリック
      if((ENUM_CHART_EVENT)id==CHARTEVENT_OBJECT_CLICK && sparam!=m_name)
        {
         ObjectSetInteger(0,m_name,OBJPROP_SELECTED,0);
         ChartRedraw();
        }
     }
   return(res);
  }

X軸とY軸のトレンドラインの子クラスを使用することが当初の計画でした。しかし、「角度による近似曲線」では、目的の完璧な解決策が明らかになりました。MQL5のドキュメントを読み、この強力なツールを発見しました。角度により近似曲線を描画すると、一度時間枠を切り替えた場合でも、変わりません。

結論: マニュアルを熟読すれば、便利な関数やツールの多くを発見するでしょう。 

 

グラフィックメモリ (GM)

論文「インジケーターバッファと配列なしヒストグラムの形で統計分布」では、グラフィック メモリと例について説明します。ここで、基本的な原則を繰り返します。グラフィカルオブジェクトのプロパティは他のオブジェクトの使用に必要な情報を格納でき、関数をプログラムします。

次のクラスで、グラフィックメモリのプログラミングと実用的なアプリケーションを容易に作成できました。

class CGM
  {
private:
public:
   string            m_name;        //グラフィカルオブジェクトの名前
                     CGM(){}
                    ~CGM(){}
   void              Create(string name) {m_name=name;}
   //OBJPROP_PRICE プロパティを読み取る
   double            R_OBJPROP_PRICE(int prop_modifier=0)
     {
      return(ObjectGetDouble(0,m_name,OBJPROP_PRICE,prop_modifier));
     }
   //OBJPROP_TIME プロパティを読み取る
   datetime          R_OBJPROP_TIME(int prop_modifier=0)
     {
      return((datetime)ObjectGetInteger(0,m_name,OBJPROP_TIME,prop_modifier));
     }
   //OBJPROP_ANGLE プロパティを読み取る
   double            R_OBJPROP_ANGLE()
     {
      return(ObjectGetDouble(0,m_name,OBJPROP_ANGLE));
     }
   //OBJPROP_TEXT プロパティを読み取る
   string            R_OBJPROP_TEXT()
     {
      return(ObjectGetString(0,m_name,OBJPROP_TEXT));
     }
   //指定された時間の価格値を返します
   double            R_ValueByTime(datetime time)
     {
      return(ObjectGetValueByTime(0,m_name,time));
     }
   //OBJPROP_TEXT プロパティの書き込み
   void              W_OBJPROP_TEXT(string text)
     {
      ObjectSetString(0,m_name,OBJPROP_TEXT,text);
     }
  };

コードからもわかるように、グラフィカルオブジェクトのプロパティを読み書きするメソッドが含まれます。このクラスは、作成中にグラフィカルオブジェクトにリンクされて、メッセージを必要とするインタラクティブ型グラフィカルオブジェクトに必要な情報を送受信できます。例

  • グラフィックメモリ クラスAAのインスタンスを、リンク先となるAと呼ばれる 3D オブジェクトに作成しました。
  • 今、AAからAオブジェクトに関する必要な情報を得ることができる 3D オブジェクトBを作成します。オブジェクトABのインスタンス間の直接のリンクはありませんが、AAクラスにより、AからBへの重要なデータの伝送を実現できます。
  • Bオブジェクトを作成しているときは、 BBグラフィック メモリ クラスのインスタンスが作成されます。Aオブジェクトは、Bオブジェクトの必要な情報にアクセスできます。
  • などなど。オブジェクトの数は限られており、各オブジェクトがグラフィック メモリ クラスのインスタンスを使用して情報を送受信することができます。

グラフィック メモリは需要と供給にある特定の情報の通知が配置されている掲示板として比喩的に表すことができます。このメソッドは、インタラクティブなグラフィカルオブジェクト間のデータ交換をもたらします。3Dモデル設計の段階で、データが3Dオブジェクトデータの正確な性能に必要になります。最も貴重な情報は、全体の 3 D オブジェクトの「パック」する必要があります。プロパティ、3次元空間内のポジションの変更、回転、座標の中心の移動に属しています。

インタラクティブな座標システムCUSCのクラスのグラフィック メモリの使用メソッドを参照してください。

座標系

3次元視覚的分析では、3次元空間データを分析することができます。 たとえば、1つか複数のソース データ シーケンス (観察) の3次元画像を構築する変数を選択します。選択した変数はY軸に沿って、観測はY軸に沿って表示されます。 変数の値がZ軸に沿ってプロットされます。

このような 3 次元のチャートを使用して、変数の値のシーケンスを視覚化します。

2次元と比較して立体表現の主な利点は、複数のチャートを3次元画像を用いたデータセットの個別の値のシーケンスの認識が簡単です。インタラクティブな回転を使用して、選択することができます。正しい角度でチャートの線は重複せず、しばしば複数の線チャートに2次元的に起こる別の表示ではありません。 

3Dモデリングに進む前に、座標システムを見てみましょう。「図」と「キャンバス」の2つの座標系は、MQL5言語開発者によって提供されています。さらに、3次元システム (アクソノ メトリック投影) を実装します。よって、違いと目的について考えてみよう。

図2。「チャート」の座標系。

図2。「チャート」の座標系。

「チャート」の座標系 (図2) 。価格データ、時系列インジケーターを表示するための2次元座標システムです。タイム スケールは水平軸上に位置して、右に左から送られます。垂直軸は、金融商品の価格です。MQL5グラフィカルオブジェクトのほとんどは、この座標システムで動作します。現在の価格とバーは同じ垂直軸上にあり、チャートが左にシフトされて自動的に新しいバーが表示されたら、移動します。

図3。「キャンバス」の座標系。

図3。「キャンバス」の座標系。

「キャンバス」座標システム (図3).画面上の各ポイントは、1ピクセルに対応します。点の座標は、チャートの左上隅からカウントされます。このシステムはまた、2次元と時系列にリンクされていないオブジェクトを使用しています。この記事ではこのシステムを使用しません。

図4。3次元座標系。

図4。3次元座標系。

3次元座標系 (図4).この座標系では、3 つの軸は互いに垂直です。しかし、「キャンバス」座標系では、XYZ 軸の間の角度は90 度ではありません。たとえば、 XYは、120 度の角度を形成します。この角度は変わるかもしれませんが、 この記事では上記の値を使用します。

Z軸は現在のバーにリンクされ、「チャート」の座標システムの「価格」のスケールに対応する軸のスケールです。Z軸の別のスケールを作成する必要がないので非常に便利です。代わりに、「価格」のスケールを使用できますZ = 価格

X軸は左から右、すなわち「チャート」の座標システムの「時間」のスケールの反対側に送られます。この記事に沿ってBar変数の値が表示されます。X軸上の任意のバーの投影は、その値に等しくなります。 (X = Bar)。

Y軸は、一連の 2 次元の XZ データに使用されます。たとえば、オープンクローズ時間シリーズのこの軸線をプロットすることができ、それぞれの行を別の平面上で検索します。YZ平面に平行の行のすべてのポイントを接続することにより、3次元の時間シリーズ オブジェクト (図5参照) すなわちグリッドが表示されます。 

図53次元の座標システムによる3Dオブジェクト。

図53次元の座標システムによる3Dオブジェクト。

 

インタラクティブな座標系: クラス CUSC

CIGO基本クラスから派生します。 

class CUSC:public CIGO
  {
private:
   datetime          m_prev_bar;
   datetime          m_next_bar;
   //---
   C_OBJ_ARROW_RIGHT_PRICE Centr;   //C_OBJ_ARROW_RIGHT_PRICE クラスのインスタンスを宣言する
   C_OBJ_TREND       AxisZ;         //C_OBJ_TREND クラスのインスタンスを宣言する
   C_OBJ_TRENDBYANGLE AxisY,AxisX;  //C_OBJ_TRENDBYANGLE クラスのインスタンスを宣言する
   //---
   CGM               gCentr;        //CGM のクラスのインスタンスを宣言する
   CGM               gAxisY,gAxisX; //CGM のクラスのインスタンスを宣言する

public:
                     CUSC();
                    ~CUSC();
   //---Z 座標を計算する
   sPointCoordinates Z(double price,   //「チャート」の座標系での価格
                       int barX,       //X 軸に沿ったシフト
                       int barY);      //Y 軸に沿ったシフト
   //---新しいバー
   bool on_bar()
     {
      m_next_bar=T(0);
      if(m_next_bar>m_prev_bar)
        {
         m_prev_bar=m_next_bar;
         return(true);
        }
      return(false);
     }
   //---
   virtual     //メソッド: IGOオブジェクトを作成する
   void              Create(string name);
   virtual     //処理メソッド OnChartEvent
   void              OnEvent(const int id,
                             const long &lparam,
                             const double &dparam,
                             const string &sparam);
  };

クラスの次のメソッドを詳しく見てみましょう: Z() OnEvent()Create()

Createメソッド: 3次元座標系を作成する

インタラクティブな座標系の 3 D オブジェクトを作成します。インタラクティブ関数が含まれています: Z 軸周辺の原点を移動座標系の回転。

void CUSC::Create(string name)
  {
//---3次元の座標系の中心
   Centr.Create("Axis XYZ");        //座標系の中心を作成する
   gCentr.Create(Centr.m_name);     //グラフィック メモリのオブジェクトを作成する
   m_price=gCentr.R_OBJPROP_PRICE();
//---Z 軸
   AxisZ.Create("Axis Z");          //座標系の Z 軸を作成する
//---Y 軸
   AxisY.Create("Axis Y",                 //座標系の Y 軸を作成する
                gCentr.R_OBJPROP_PRICE(), //GM から値を取得する
                30);                      //軸傾斜角を 30 度に設定
   gAxisY.Create(AxisY.m_name);           //グラフィックのメモリ オブジェクトを作成する
   m_angle=gAxisY.R_OBJPROP_ANGLE();
//---X軸
   AxisX.Create("Axis X",                       //座標系の X 軸を作成する
                gCentr.R_OBJPROP_PRICE(),       //GM から値を取得する
                gAxisY.R_OBJPROP_ANGLE()+ISO);  //GM から値を取得し、ISO 度増加
   gAxisX.Create(AxisX.m_name);                 //グラフィックのメモリ オブジェクトを作成する
//---
   ChartRedraw();
   on_event=true; //イベント処理を許可する
  }

Parameters:

 name

   [in]座標系の名前。

戻り値:

 戻り値はありません。成功した場合は、インタラクティブ型の座標系が作成されます。

 

OnEventメソッド: 受信メッセージの処理

このメソッドは、チャートを操作するときに、クライアントターミナルから受信したイベントを処理します。このメソッドは、1つの標準的なイベントにのみ応答します。グラフィカルオブジェクトを移動します。その他のイベントは、座標システムをプログラミングする際に作成されるクラスのすべてのインスタンスに送信されます。

void CUSC::OnEvent(const int id,
                   const long &lparam,
                   const double &dparam,
                   const string &sparam)
  {
   if(on_event) //イベント処理を許可
     {
      //---OnChartEvent イベントを渡す
      AxisZ.OnEvent(id,lparam,dparam,sparam);
      //---
      if(Centr.OnEvent(id,lparam,dparam,sparam))
        {//グラフィカルオブジェクトを移動する
         AxisY.OnEvent(id,lparam,dparam,sparam,Event_1,gCentr.R_OBJPROP_PRICE());
         AxisX.OnEvent(id,lparam,dparam,sparam,Event_1,gCentr.R_OBJPROP_PRICE());
        }
      else
        {
         if(AxisY.OnEvent(id,lparam,dparam,sparam))
           {//グラフィカルオブジェクトの角度を変更する
            AxisX.OnEvent(id,lparam,dparam,sparam,Event_2,gAxisY.R_OBJPROP_ANGLE()+ISO);
           }
         else
           {
            if(AxisX.OnEvent(id,lparam,dparam,sparam))
              {//グラフィカルオブジェクトの角度を変更する
               AxisY.OnEvent(id,lparam,dparam,sparam,Event_2,gAxisX.R_OBJPROP_ANGLE()-ISO);
              }
           }
        }
      ChartRedraw();
      m_price=gCentr.R_OBJPROP_PRICE();
      m_angle=gAxisY.R_OBJPROP_ANGLE();
     }
  }

Parameters: 

 id

   [in]イベント id このメソッドを使用して処理できるイベントには 9 種類あります。

 lparam

   [in]Long 型のイベント パラメータ。

 dparam

   [in]Double 型のイベント パラメータ。

 sparam

   [in]文字列型のイベント パラメータ。

 iparametr

   [in]カスタム イベントの識別子です。

 dparametr

   [in]Long 型のカスタム イベントのパラメータ。

戻り値:

 戻り値はありません。

 

座標 (sPointCoordinates) の値を受信するための構造。

「チャート」座標系における座標の値を格納するための構造。この構造は、3Dの点の座標を取得できます。 

struct sPointCoordinates
  {
   datetime          time;    //「チャート」システムの座標
   double            price;   //「チャート」システムの座標
  };

SPointCoordinates型の変数は、 Z()関数の 1 回の呼び出しでチャートの座標システムで 3 D の点の座標を得ることができます。

 

Zメソッド: Z座標を計算します。 

このメソッドは、Z 座標を計算します。

sPointCoordinates CUSC::Z(double price,int barX,int barY)
  {
   sPointCoordinates res;
   res.price=0;
   res.time=0;
   double dX,dY;
   dX=0;
   dX=gAxisX.R_ValueByTime(T(barX))-m_price;
   dY=0;
   dY=gAxisY.R_ValueByTime(T(-barY))-m_price;
   res.price=price+dX-dY;
   res.time=T(barX-barY);
   return(res);
  }

Parameters: 

 price

   [in]3 D オブジェクトの Z 座標。

 barX

   [in]3 D オブジェクトの X 座標。値は、足で設定されます。

 barY

   [in]3 D オブジェクトの Y 座標。値は、足で設定されます。

戻り値:

  この関数が成功した場合は、sPointCoordinates 型の変数の値が返されます。

 

グリッドフォームの3Dサーフェスを作成します。

たとえば、次の関数に基づく3次元表面の構築を考えてみましょう。

fun[i][j]=close[i*StepX]-_Point*j*j
実用的な意味を提供する数式がない、シンプルなデモンストレーションです。コードは簡潔です。さまざまなスキルレベルのプログラマが様々な実験に使用することができます。このインジケーターチャートは特定の関数に基づく 3 D グリッドを得ることで起動します。(参照図6)。Y軸とX軸の角度を変更することによって、ビューのポイントを変更できます。実際に、オブジェクトのZ軸を回転します。座標の中心に移動し、モデルのカラーリングが変更されます: 0Z軸に沿ってノードの値が超える場合、赤。下回る場合、青。
//---定数の宣言
#define  StepX    10    //[Bar] X 軸に沿ったステップ
#define  StepY    5     //Y軸[bar] ステップ
#define  _X       50    //X軸に沿ったポイントの数
#define  _Y       15    //Y 軸に沿ったポイントの数
#define  W1       1     //線幅
#define  W2       3     //最後の行の幅
//---クラスのファイルを含む
#include<3D\USC.mqh >
//---
#propertyindicator_chart_window
//---インジケーターの計算に対するバッファの数
#propertyindicator_buffers0
//---インジケーターのグラフィカルな系列の数
#propertyindicator_plots 0
//---
CUSC        USC;
double fun[_X][_Y];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
intOnInit()
  {
   USC.Create("3D");
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//カスタム インジケーター繰り返し関数 |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   ArraySetAsSeries(close,true);
//---3 D 表面関数
   for(int i=0;i<_X;i++)
      for(int j=0;j<_Y;j++)
        {
         fun[i][j]=close[i*StepX]-_Point*j*j;
         //fun[i][j]=close[i*StepX]-_Point*j*j*i/7;
        }

//---X 線
   for(int i=1;i<_X;i++)
      for(int j=0;j<_Y;j++)
        {
         sPointCoordinates a0=USC.Z(fun[(i-1)][j], //関数
                                    (i-1)*StepX,   //X
                                    -j*StepY);     //Y
         sPointCoordinates a1=USC.Z(fun[i][j],     //関数
                                    i*StepX,       //X
                                    -j*StepY);     //Y
         string name="line x "+"x"+(string)i+"y"+(string)+j;
         ObjectCreate(0,name,OBJ_TREND,0,a0.time,a0.price,a1.time,a1.price);
         if(fun[i][j]>USC.m_price && fun[i-1][j]>USC.m_price)
            ObjectSetInteger(0,name,OBJPROP_COLOR,clrRed);
         else
            ObjectSetInteger(0,name,OBJPROP_COLOR,clrBlue);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,W1);
         if(j==0 || j==_Y-1)
            ObjectSetInteger(0,name,OBJPROP_WIDTH,W2);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID);
         ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,false);
         ObjectSetInteger(0,name,OBJPROP_RAY_LEFT,false);
         ObjectSetInteger(0,name,OBJPROP_BACK,true);
         ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
        }
//---Y ライン
   for(int i=0;i<_X;i++)
      for(int j=1;j<_Y;j++)
        {
         sPointCoordinates a0=USC.Z(fun[i][j-1],   //関数
                                    i*StepX,       //X
                                    -(j-1)*StepY); //Y
         sPointCoordinates a1=USC.Z(fun[i][j],     //関数
                                    i*StepX,       //X
                                    -j*StepY);     //Y
         string name="line y "+"x"+(string)i+"y"+(string)+j;
         ObjectCreate(0,name,OBJ_TREND,0,a0.time,a0.price,a1.time,a1.price);
         ObjectSetInteger(0,name,OBJPROP_COLOR,clrGreen);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID);
         ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,false);
         ObjectSetInteger(0,name,OBJPROP_RAY_LEFT,false);
         ObjectSetInteger(0,name,OBJPROP_BACK,true);
         ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
        }
//---次の呼び出しの prev_calculated の戻り値
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   USC.OnEvent(id,lparam,dparam,sparam);
  }

XZ 平面、YZ 平面に線を描き分けています。各軸および関数自体の数を変更することができます。

図6。3D サーフェスを描画します。

図6。3D サーフェスを描画します。

図7。3D 移動平均を描画します。

図7。3D 移動平均を描画します。 

ここで、批判的な方へ。なぜ3Dモデリングが必要で、どのようにトレードに役に立つのでしょうか。

もちろん、MT5 ターミナルは、金融相場でトレードするため設計されています。トレーダーとトレードシステムの開発者は、トレーディングアルゴリズムと収益性の高い戦略の作成に興味があります。技術もまだ初期段階で、潜在的な投資家にトレードアイデアや戦略を表現するため、3Dモデリングを使用ことができます。さらに、ターミナルは、相場情報の流れに対応し、3Dのインジケーターを作成することができます。 時間をかけて自分のフォームを変更するダイナミックな3Dモデルを作成することができます。

これはWindows に似ています。システムの最初のバージョンは遅く、クロッキーでした。ノートンのファンはグラフィカル ・ インタフェースには懐疑的だった。NCは今どうなりましたか。

結論

  1. 3Dモデリングは多くのプログラミング環境で困難なタスクです。しかし、トレーディングターミナルの3次元可視化を実装することができる強力な関数をユーザーを提供します。
  2. 3Dオブジェクトクラスのライブラリのプログラミングの最初の結果だけを受けています。3Dモデリングスフィアは、その可能性のすべてをカバーするのには広大すぎます。うまくいけば、3Dモデリング信者が、3D方向のトレードや MQL5 をプログラミングを開発する方法を提案することでしょう。
  3. この記事で作成した3Dモデリングツールは、技術的な分析における新たな方向性に大きな影響を持ちます。3次元インジケーターとその分析です。
  4. レンダリングの速度に問題がありますが、ライブラリの開発のこの段階では重要ではありません。
  5. この記事では、3Dオブジェクトの作成の原則は、OpenCL におそらく転送できます。

注意:

ライブラリ ファイルの保存先は..\Include\3D folderです。