English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
preview
MetaTrader 5'te DirectX’i kullanarak 3D grafikler nasıl oluşturulur?

MetaTrader 5'te DirectX’i kullanarak 3D grafikler nasıl oluşturulur?

MetaTrader 5Entegrasyon | 31 Ekim 2022, 09:23
484 0
MetaQuotes
MetaQuotes

3D bilgisayar grafikleri, nesnelerin düz bir ekranda üç boyutlu uzayda olacak şekilde görüntülenmesiyle ilgilidir. İlgili nesnelerin ve izleyicinin konumu zaman içerisinde değişebilir. Buna dayalı olarak, iki boyutlu görüntü de değişmeli, derinlik yanılsaması yaratmaya devam etmelidir - dönme, hareket, ışıklandırma değişiklikleri ve benzeriyle. MQL5 dili, DirectX fonksiyonları kullanılarak doğrudan MetaTrader 5 terminalinde bilgisayar grafiklerinin oluşturulmasına ve yönetilmesine olanak sağlar. Bu işlevlerin çalışması için ekran kartınızın DX 11 ve Shader Model 5.0'ı desteklemesi gerektiğini lütfen unutmayın.


Nesne modelleme

Düz bir yüzey üzerine üç boyutlu bir nesne çizebilmek için öncelikle bu nesnenin X, Y ve Z koordinatlarında modelini oluşturmak gerekir. Bu, nesne yüzeyindeki her noktanın koordinatlar cinsinden tanımlanması gerektiği anlamına gelir. İdeal olarak, ölçeklendirme sırasında görüntü kalitesinin kaybolmaması amacıyla nesne yüzerinde sonsuz sayıda nokta tanımlamak gerekir. Pratikte, 3D modeller çokgenlerden oluşan bir ağ kullanılarak tanımlanır. Ağ ne kadar çok çokgen içerirse, model o kadar gerçekçi olur. Ancak, böyle bir modeli hesaplamak ve 3D grafikler oluşturmak için çok daha fazla bilgisayar kaynağı gerekir.

Çokgen ağ olarak bir çaydanlık modeli

Çokgenlerden oluşan bir ağ şeklinde çaydanlık modeli

Başlangıçta, bilgisayarlar ve ekran kartları günümüzdeki kadar güçlü olmadığı zamanlarda, çokgenleri üçgenlere bölme fikri ortaya çıkmıştır. Üçgen yardımıyla, küçük yüzey alanının konumunu tam olarak tanımlamak ve ışık yansımaları gibi gerekli parametreleri hesaplamak mümkün olmaktadır. Bu tür birçok küçük üçgenin kombinasyonu, nesnenin gerçekçi bir üç boyutlu görüntüsünün oluşturulmasına olanak sağlar. Bir üçgeni hayal etmek N köşeli bir çokgeni hayal etmekten çok daha kolay olduğu için, buradan itibaren çokgen ve üçgen eşanlamlı olarak kullanılacaktır.


Üçgenlerden oluşan bir küp

Üçgenlerin her bir köşesinin koordinatları tanımlanarak, nesnenin üç boyutlu bir modeli oluşturulabilir, bu da nesne hareket etse veya izleyicinin konumu değişse bile, nesnenin her bir noktasının koordinatlarının devamlı olarak hesaplanmasına olanak tanır. Üçgenler, köşelere (vertex), onları birbirine bağlayan kenarlara (edge) ve kenarların oluşturduğu yüzlere (face) sahiptir. Üçgenin uzaydaki konumunu biliyorsak, lineer cebir yasalarını kullanarak yüzey için bir normal oluşturabiliriz (normal, yüzeye dik olan vektördür). Bu, üçgenin yüzü üzerindeki ışık yansımalarının hesaplanmasını mümkün kılar.


Köşeleri, kenarları, yüzleri ve normalleri olan basit nesne örnekleri. Normal, kırmızı okla gösterilmektedir.

Bir nesnenin modeli farklı şekillerde oluşturulabilir. Topoloji, çokgenlerin nasıl bir 3D ağ oluşturduğunu açıklar. İyi bir topoloji, nesneyi tanımlamak için minimum sayıda çokgen kullanılmasına olanak sağlar ve nesnenin uzayda hareket ettirilmesini ve döndürülmesini kolaylaştırır.

İki topolojide küre modeli

İki topolojide küre modeli

Bir nesneyi üç boyutlu yapan şey, çokgenler üzerindeki ışık ve gölge oyunudur. İşte bu, 3D bilgisayar grafiklerinin görevidir: nesnenin her noktasının uzaydaki konumunu hesaplamak, ışık yansımalarını hesaplamak ve ardından onu ekranda görüntülemek.

Şekil oluşturma

Bir küp oluşturan basit bir program yazalım. Bunu yapmak için 3D grafik kütüphanesinden CCanvas3D sınıfını kullanacağız.

CCanvas3DWindow sınıfı, 3D pencere çizmek için yeterli minimum üyeye ve metoda sahiptir. Ayrıca, DirectX ile çalışmak için fonksiyonlarda uygulanan 3D grafik kavramlarıyla giderek yeni metotlar da ekleyeceğiz.

//+------------------------------------------------------------------+
//| Application window                                               |
//+------------------------------------------------------------------+
class CCanvas3DWindow
  {
protected:
   CCanvas3D         m_canvas;
   //--- canvas size
   int               m_width;
   int               m_height;
   //--- the Cube object
   CDXBox            m_box;

public:
                     CCanvas3DWindow(void) {}
                    ~CCanvas3DWindow(void) {m_box.Shutdown();}
   //-- create a scene
   virtual bool      Create(const int width,const int height){}
   //--- calculate the scene
   void              Redraw(){}
   //--- handle chart events
   void              OnChartChange(void) {}
  };

Sahnenin oluşturulması önce tuvalin oluşturulmasıyla başlar. Ardından projeksiyon matrisi için aşağıdaki parametreler ayarlanır:

  1. 3D sahneye baktığımız 30 derecelik bakış açısı (M_PI/6)
  2. Genişliğin yüksekliğe oranı
  3. Yakın (0.1f) ve uzak (100.f) kırpma düzlemine olan mesafe

Bu, yalnızca ilgili iki sanal duvar (0.1f ve 100.f) arasındaki nesnelerin projeksiyon matrisinde görüntüleneceği ve ayrıca nesnelerin yatay 30 derecelik bakış açısı içerisinde olması gerektiği anlamına gelir. Bilgisayar grafiklerinde mesafeler ve genel olarak konuşursak tüm koordinatlar sanaldır. Çünkü, önemli olan mutlak değerler değil, mesafeler ve boyutlar arasındaki ilişkilerdir.

   //+------------------------------------------------------------------+
   //| Create                                                           |
   //+------------------------------------------------------------------+
   virtual bool      Create(const int width,const int height)
     {
      //--- save canvas dimensions
      m_width=width;
      m_height=height;
      //--- create a canvas to render a 3D scene
      ResetLastError();
      if(!m_canvas.CreateBitmapLabel("3D Sample_1",0,0,m_width,m_height,COLOR_FORMAT_ARGB_NORMALIZE))
        {
         Print("Error creating canvas: ",GetLastError());
         return(false);
         }
      //--- set projection matrix parameters - angle of view, aspect ratio, distance to the near and far clip planes
      m_canvas.ProjectionMatrixSet((float)M_PI/6,(float)m_width/m_height,0.1f,100.0f);
      //--- create cube - pass to it the resource manager, scene parameters and coordinates of two opposite corners of the cube
      if(!m_box.Create(m_canvas.DXDispatcher(),m_canvas.InputScene(),DXVector3(-1.0,-1.0,5.0),DXVector3(1.0,1.0,7.0)))
        {
         m_canvas.Destroy();
         return(false);
         }
      //--- add the cube to the scene
      m_canvas.ObjectAdd(&m_box);
      //--- redraw the scene
      Redraw();
      //--- succeed
      return(true);
      }

Projeksiyon matrisini oluşturduktan sonra, CDXBox sınıfına dayalı bir küp olan 3D nesneyi oluşturmaya devam edebiliriz. Bir küp oluşturmak için, küpün zıt köşelerine işaret eden iki vektör belirtmek gerekli ve yeterlidir. Hata ayıklama modunda küpün oluşturulma sürecini izlersek, DXComputeBox() metodunda neler olduğunu görebiliriz: küpün tüm köşelerinin oluşturulması (koordinatları vertices dizisine yazılır) ve küpün yüzlerinin üçgenlere bölünmesi (üçgenlerin köşeleri numaralandırılır ve indiсes dizininde depolanır). Küpün toplamda 8 köşesi, 12 üçgene bölünmüş 6 yüzü ve bu üçgenlerin köşelerini numaralandıran 36 indeksi vardır.

Küpün yalnızca 8 köşesi olmasına rağmen, tam açıklama için 24 vektör oluşturulur, çünkü 6 yüzün her biri için kendi normalleri olan ayrı köşe kümesi belirtilmesi gerekir. Normalin yönü, her bir yüzün ışıklandırmasının hesaplanmasını etkileyecektir. Üçgenlerin köşelerinin numaralandırılma sırası, hangi kenarların görünür olacağını belirler. Köşelerin ve indekslerin doldurulma sırası DXUtils.mqh kodunda gösterilmektedir:

   for(int i=20; i<24; i++)
      vertices[i].normal=DXVector4(0.0,-1.0,0.0,0.0);

Ayrıca, her yüzün doku kaplaması için doku koordinatları da aynı kodda açıklanmaktadır:

//--- texture coordinates
   for(int i=0; i<faces; i++)
     {
      vertices[i*4+0].tcoord=DXVector2(0.0f,0.0f);
      vertices[i*4+1].tcoord=DXVector2(1.0f,0.0f);
      vertices[i*4+2].tcoord=DXVector2(1.0f,1.0f);
      vertices[i*4+3].tcoord=DXVector2(0.0f,1.0f);
      }

4 yüz vektörünün her biri, doku kaplama için 4 açıdan birini belirler. Bu, görüntüleme sırasında küpün her yüzüne kare bir yapının gerilerek çizileceği anlamına gelir. Elbette, buna yalnızca doku ayarlanmışsa ihtiyaç vardır.


Sahne hesaplama ve görüntüleme

3D sahne her değiştiğinde, tüm hesaplamaların yeniden yapılması gerekir. Bu, gerekli hesaplamaların bir sırayla yapılması gerektiği anlamına gelir:

  • Nesnenin merkezinin dünya koordinatlarında konumu
  • Nesnenin her bir elemanının, yani her bir köşesinin konumu
  • Piksel derinliği ve izleyiciye görünürlüğü
  • Çokgenler üzerindeki her pikselin konumu
  • Çokgenler üzerindeki her pikselin belirtilen dokuya dayalı rengi
  • Piksele düşen ışığın yönü ve ondan yansıması
  • Her piksele dağınık ışık uygulanması
  • Tüm dünya koordinatlarının kamera koordinatlarına dönüştürülmesi
  • Kamera koordinatlarının projeksiyon matrisindeki koordinatlara dönüştürülmesi
Tüm bu hesaplamalar CCanvas3D nesnesinin Render metodunda gerçekleştirilir. Bu hesaplamalardan sonra elde edilen görüntü, Update metodu çağrılarak projeksiyon matrisinden tuvale aktarılır.
   //+------------------------------------------------------------------+
   //| Update the scene                                                 |
   //+------------------------------------------------------------------+
   void              Redraw()
     {
      //--- calculate the 3D scene
      m_canvas.Render(DX_CLEAR_COLOR|DX_CLEAR_DEPTH,ColorToARGB(clrBlack));
      //--- update the picture on the canvas in accordance with the current scene
      m_canvas.Update();
      }

Örneğimizde, küp yalnızca bir kez oluşturulmaktadır ve üzerinde başka bir değişiklik olmamaktadır. Dolayısıyla, tuval üzerindeki çerçevenin yalnızca yeniden boyutlandırma gibi fiyat grafiğinde değişiklikler olduğunda güncellenmesi gerekecektir. Böyle bir değişiklik durumunda, tuval boyutu mevcut fiyat grafiği boyutlarına göre ayarlanır, projeksiyon matrisi sıfırlanır ve tuval üzerindeki görüntü güncellenir.

   //+------------------------------------------------------------------+
   //| Process chart change event                                       |
   //+------------------------------------------------------------------+
   void              OnChartChange(void)
     {
      //--- get current chart sizes
      int w=(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS);
      int h=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS);
      //--- update canvas dimensions in accordance with the chart size
      if(w!=m_width || h!=m_height)
        {
         m_width =w;
         m_height=h;
         //--- resize canvas
         m_canvas.Resize(w,h);
         DXContextSetSize(m_canvas.DXContext(),w,h);
         //--- update projection matrix in accordance with the canvas sizes
         m_canvas.ProjectionMatrixSet((float)M_PI/6,(float)m_width/m_height,0.1f,100.0f);
         //--- recalculate 3D scene and render it onto the canvas
         Redraw();
         }
      }

Step1 Create Box.mq5 Uzman Danışmanını başlatalım. Siyah arka plan üzerinde beyaz bir kare görüyoruz. Varsayılan olarak, nesneler oluşturulurken renk beyaz olarak ayarlanır. Işıklandırmayı henüz ayarlamadık.

Beyaz küp ve uzaydaki yerleşimi

Beyaz küp ve uzaydaki yerleşimi

Burada, X ekseni sağa doğru, Y ekseni yukarı doğru ve Z ekseni de 3D sahnenin içerisine doğru yönlü haldedir. Böyle bir koordinat sistemi solak olarak adlandırılır.

Küpün merkezi, koordinatları X=0, Y=0 ve Z=6 olan noktadadır. Küpe baktığımız konum, varsayılan değer olan koordinatların merkezindedir. Bakış noktasının konumunu değiştirmek istiyorsak, ViewPositionSet() fonksiyonunu kullanarak uygun koordinatları açıkça ayarlamalıyız.

Programdan Escape tuşuyla çıkılabilir.


Nesnenin Z ekseni ve bakış noktası etrafında döndürülmesi

Sahneyi biraz canlandırmak için küpü Z ekseni etrafında döndürelim. Bunu yapmak için bir zamanlayıcı ekleyelim - olaylarına bağlı olarak küp saat yönünün tersine döndürülecektir.

Nesnenin Z ekseni etrafında belirli bir açıyla dönmesini sağlamak adına DXMatrixRotationZ() metodunu kullanarak bir dönme matrisi oluşturalım. Ardından onu TransformMatrixSet() metoduna parametre olarak iletelim. Bu, küpün uzaydaki konumunu değiştirecektir. Devamında da tuval üzerindeki görüntüyü güncellemek için tekrar Redraw() fonksiyonunu çağıralım.

   //+------------------------------------------------------------------+
   //| Timer handler                                                    |
   //+------------------------------------------------------------------+
   void              OnTimer(void)
     {
      //--- variables for calculating the rotation angle
      static ulong last_time=0;
      static float angle=0;
      //--- get the current time
      ulong current_time=GetMicrosecondCount();
      //--- calculate the delta
      float deltatime=(current_time-last_time)/1000000.0f;
      if(deltatime>0.1f)
         deltatime=0.1f;
      //--- increase the angle of rotation of the cube around the Z axis
      angle+=deltatime;
      //--- remember the time
      last_time=current_time;
      //--- set the angle of rotation of the cube around the Z axis
      DXMatrix rotation;
      DXMatrixRotationZ(rotation,angle);
      m_box.TransformMatrixSet(rotation);
      //--- recalculate 3D scene and render it onto the canvas
      Redraw();
      }

Çalıştırdıktan sonra dönen beyaz bir kare göreceğiz.

Küp Z ekseni etrafında saat yönünün tersine dönmektedir

Bu örneğin kaynak kodu Step2 Rotation Z.mq5 dosyasındadır. Sahne oluşturulurken artık M_PI/5 açısının belirtildiğine ve bu açının önceki örnekteki M_PI/6 açısından daha büyük olduğuna lütfen dikkat edin. 

      //--- set projection matrix parameters - angle of view, aspect ratio, distance to the near and far clip planes
      m_matrix_view_angle=(float)M_PI/5;
      m_canvas.ProjectionMatrixSet(m_matrix_view_angle,(float)m_width/m_height,0.1f,100.0f);
      //--- create cube - pass to it the resource manager, scene parameters and coordinates of two opposite corners of the cube

Ancak aynı zamanda ekrandaki küpün boyutu da görsel olarak küçülmüştür. Projeksiyon matrisi ayarlanırken belirtilen bakış açısı ne kadar küçük olursa, nesne tarafından o kadar büyük çerçeve alanı işgal edilir. Bu, nesnelere teleskopla bakmaya benzetilebilir: bakış açısı daha küçük olmasına rağmen nesne daha büyük görülür.


Kamera konumu yönetimi

CCanvas3D sınıfı, 3D sahnenin önemli parametrelerini ayarlamak için birbirine bağlı üç metoda sahiptir:

Tüm bu parametreler birlikte kullanılır, yani 3D sahnede bu parametrelerden herhangi birini ayarlamak istiyorsak, diğer iki parametrenin de başlatılması gerekir. Bu, en azından sahne oluşturma aşamasında yapılmalıdır. Bunu, çerçevenin üst sınırının sağa ve sola sallandığı aşağıdaki örnekte göstereceğiz. Bu amaçla Create() metoduna aşağıdaki üç satırı ekleyelim:

   //+------------------------------------------------------------------+
   //| Create                                                           |
   //+------------------------------------------------------------------+
   virtual bool      Create(const int width,const int height)
     {
....       
      //--- add the cube to the scene
      m_canvas.ObjectAdd(&m_box);
      //--- set the scene parameters
      m_canvas.ViewUpDirectionSet(DXVector3(0,1,0));  // set the direction vector up, along the Y axis  
      m_canvas.ViewPositionSet(DXVector3(0,0,0));     // set the viewpoint from the center of coordinates
      m_canvas.ViewTargetSet(DXVector3(0,0,6));       // set the gaze point at center of the cube      
      //--- redraw the scene
      Redraw();
      //--- succeed
      return(true);
      }

OnTimer() metodunu, ufuk vektörünün sağa ve sola sallanmasını sağlayacak şekilde değiştirelim.

   //+------------------------------------------------------------------+
   //| Timer handler                                                    |
   //+------------------------------------------------------------------+
   void              OnTimer(void)
     {
      //--- variables for calculating the rotation angle
      static ulong last_time=0;
      static float max_angle=(float)M_PI/30;
      static float time=0;
      //--- get the current time
      ulong current_time=GetMicrosecondCount();
      //--- calculate the delta
      float deltatime=(current_time-last_time)/1000000.0f;
      if(deltatime>0.1f)
         deltatime=0.1f;
      //--- increase the angle of rotation of the cube around the Z axis
      time+=deltatime;
      //--- remember the time
      last_time=current_time;
      //--- set the rotation angle around the Z axis
      DXVector3 direction=DXVector3(0,1,0);     // initial direction of the top
      DXMatrix rotation;                        // rotation vector      
      //--- calculate the rotation matrix 
      DXMatrixRotationZ(rotation,float(MathSin(time)*max_angle));
      DXVec3TransformCoord(direction,direction,rotation);
      m_canvas.ViewUpDirectionSet(direction);   // set the new direction of the top
      //--- recalculate 3D scene and render it onto the canvas
      Redraw();
      }

Örneği Step3 ViewUpDirectionSet.mq5 olarak kaydedelim ve çalıştıralım. Aslında hareketsiz olmasına rağmen sallanan bir küp görüyoruz. Bu efekt, kameranın kendisi sağa ve sola sallandığında elde edilir.

Üst sınır sağa ve sola sallanmaktadır

Üst sınır sağa ve sola sallanmaktadır

Kameranın koordinatı, hedefin koordinatı ve üst sınırın yönü arasında bağlantı olduğunu lütfen unutmayın. Dolayısıyla, kameranın konumunu kontrol etmek için, bakışın yönlendirildiği hedefin koordinatının ve üst sınırın yönünün de ayarlanması gerekir.


Nesne rengi yönetimi

Kodumuzu şu şekilde değiştirelim: küpü koordinatların merkezine koyalım ve kamerayı hareket ettirelim.

   //+------------------------------------------------------------------+
   //| Create                                                           |
   //+------------------------------------------------------------------+
   virtual bool      Create(const int width,const int height)
     {
  ...
      //--- create cube - pass to it the resource manager, scene parameters and coordinates of two opposite corners of the cube
      if(!m_box.Create(m_canvas.DXDispatcher(),m_canvas.InputScene(),DXVector3(-1.0,-1.0,-1.0),DXVector3(1.0,1.0,1.0)))
        {
         m_canvas.Destroy();
         return(false);
         }
      //--- set the color 
      m_box.DiffuseColorSet(DXColor(0.0,0.5,1.0,1.0));        
      //--- add the cube to the scene
      m_canvas.ObjectAdd(&m_box);
      //--- set positions for camera, gaze and direction of the top
      m_canvas.ViewUpDirectionSet(DXVector3(0.0,1.0,0.0));  // set the direction vector up, along the Y axis
      m_canvas.ViewPositionSet(DXVector3(3.0,2.0,-5.0));    // set camera on the right, on top and in front of the cube
      m_canvas.ViewTargetSet(DXVector3(0,0,0));             // set the gaze direction at center of the cube
      //--- redraw the scene
      Redraw();
      //--- succeed
      return(true);
      }

Ayrıca küpü maviye boyayalım. Renk, alfa kanallı RGB renk formatında belirtilir (alfa kanalı en son belirtilir), ancak değerler bire normalleştirilir. Böylece, 1 değeri 255, 0,5 değeri de 127 anlamına gelir.

X ekseni etrafında dönme ekleyelim ve değişiklikleri Step4 Box Color.mq5 olarak kaydedelim.

Sağ üstten dönen küpe bakış

Sağ üstten dönen küpe bakış


Dönme ve hareket

Nesneler aynı anda üç yönde döndürülebilir ve hareket ettirilebilir. Nesnelerdeki tüm değişiklikler matrisler kullanılarak gerçekleştirilir. Ayrı ayrı olarak hesaplanabilirler - dönme ve hareket. Örneğimizi tekrar değiştirelim: bu sefer kamera küpe ön üstten bakıyor olsun.

   //+------------------------------------------------------------------+
   //| Create                                                           |
   //+------------------------------------------------------------------+
   virtual bool      Create(const int width,const int height)
     {
  ...
      m_canvas.ProjectionMatrixSet(m_matrix_view_angle,(float)m_width/m_height,0.1f,100.0f);
      //--- position the camera in top and in front of the center of coordinates
      m_canvas.ViewPositionSet(DXVector3(0.0,2.0,-5.0));
      m_canvas.ViewTargetSet(DXVector3(0.0,0.0,0.0));
      m_canvas.ViewUpDirectionSet(DXVector3(0.0,1.0,0.0));      
      //--- create cube - pass to it the resource manager, scene parameters and coordinates of two opposite corners of the cube
      if(!m_box.Create(m_canvas.DXDispatcher(),m_canvas.InputScene(),DXVector3(-1.0,-1.0,-1.0),DXVector3(1.0,1.0,1.0)))
        {
         m_canvas.Destroy();
         return(false);
         }
      //--- set the cube color
      m_box.DiffuseColorSet(DXColor(0.0,0.5,1.0,1.0));        
      //--- calculate the cube position and the transfer matrix
      DXMatrix rotation,translation;
      //--- rotate the cube sequentially along the X, Y and Z axes
      DXMatrixRotationYawPitchRoll(rotation,(float)M_PI/4,(float)M_PI/3,(float)M_PI/6);
      //-- move the cube to the right/downward/inward
      DXMatrixTranslation(translation,1.0,-2.0,5.0);
      //--- get the transformation matrix as a product of rotation and transfer
      DXMatrix transform;
      DXMatrixMultiply(transform,rotation,translation);
      //--- set the transformation matrix 
      m_box.TransformMatrixSet(transform);      
      //--- add the cube to the scene
      m_canvas.ObjectAdd(&m_box);    
      //--- redraw the scene
      Redraw();
      //--- succeed
      return(true);
      }

Sırayla dönme ve hareket matrisleri oluşturalım, elde edilen dönüşüm matrisini uygulayalım ve küpü görüntüleyelim. Değişiklikleri Step5 Translation.mq5 dosyasına kaydedelim ve çalıştıralım.

Küpte dönme ve hareket

Küpte dönme ve hareket

Kameranın hareketsiz olduğuna ve koordinatların merkezine biraz yukarıdan doğrultulduğuna dikkat edin. Küp üç yönde döndürüldü ve sağa, aşağıya ve sahnenin içerisine doğru hareket ettirildi.


Işıklandırmayla çalışma

Gerçekçi bir üç boyutlu görüntü elde etmek için nesne yüzeyindeki her noktanın ışıklandırmasının hesaplanması gerekir. Bu, şu üç ışıklandırma bileşeninin yoğunluğunu hesaplayan Phong gölgelendirme modeli kullanılarak yapılır: ortam, dağınık ve düzgün. Bu amaçla, aşağıdaki parametreler ayarlanır:

  • DirectionLight - yönlü ışıklandırmanın yönü CCanvas3D'de ayarlanır
  • AmbientLight - ortam ışıklandırmasının rengi ve yoğunluğu CCanvas3D'de ayarlanır
  • DiffuseColor - dağınık ışıklandırma bileşeni CDXMesh ve alt sınıflarında ayarlanır
  • EmissionColor - arka plan ışıklandırma bileşeni CDXMesh ve alt sınıflarında ayarlanır
  • SpecularColor - düzgün ışıklandırma bileşeni CDXMesh ve alt sınıflarında ayarlanır

Phong gölgelendirme modeli
Phong gölgelendirme modeli


Işıklandırma modeli standart gölgelendiricilerde uygulanır, model parametreleri CCanvas3D'de ayarlanır, nesne parametreleri de CDXMesh ve alt sınıflarında ayarlanır. Örneğimizi aşağıdaki gibi değiştirelim:

  1. Küpü koordinatların merkezine getirelim.
  2. Beyaza ayarlayalım.
  3. Sahneyi yukarıdan aşağıya doğru ışıklandıran yönlü sarı ışık kaynağı ekleyelim.
  4. Ortam ışıklandırması için mavi rengi ayarlayalım.
      //--- set yellow color for the source and direct it from above downwards
      m_canvas.LightColorSet(DXColor(1.0,1.0,0.0,0.8f));
      m_canvas.LightDirectionSet(DXVector3(0.0,-1.0,0.0));
      //--- set the blue color for the ambient light 
      m_canvas.AmbientColorSet(DXColor(0.0,0.0,1.0,0.4f));          
      //--- create cube - pass to it the resource manager, scene parameters and coordinates of two opposite corners of the cube
      if(!m_box.Create(m_canvas.DXDispatcher(),m_canvas.InputScene(),DXVector3(-1.0,-1.0,-1.0),DXVector3(1.0,1.0,1.0)))
        {
         m_canvas.Destroy();
         return(false);
         }
      //--- set the white color for the cube
      m_box.DiffuseColorSet(DXColor(1.0,1.0,1.0,1.0)); 
      //--- add green glow for the cube (emission)
      m_box.EmissionColorSet(DXColor(0.0,1.0,0.0,0.2f)); 

Yönlü ışık kaynağının konumunun Canvas3D'de ayarlanmadığına, yalnızca ışığın yayıldığı yönün ayarlandığına lütfen dikkat edin. Yönlü ışık kaynağının sonsuz bir mesafede olduğu ve sahneyi tam paralel bir ışık akışının ışıklandırdığı kabul edilir.

m_canvas.LightDirectionSet(DXVector3(0.0,-1.0,0.0));

Burada, ışık yayılma vektörü, Y ekseninde negatif yönde, yani yukarıdan aşağıya doğrudur. Ayrıca, yönlü ışık kaynağı için parametreler (LightColorSet ve LightDirectionSet) ayarlanırsa, ortam ışığının rengi de (AmbientColorSet) ayarlanmalıdır. Çünkü varsayılan olarak ortam ışığının rengi maksimum yoğunlukta beyaza ayarlanır ve dolayısıyla tüm gölgeler beyaz olur. Bu, sahnedeki nesnelerin ortam ışıklandırmasından gelen beyaz ışıkla dolup taşacağı, yönlü ışıklandırmanın ise beyaz ışık tarafından kesintiye uğrayacağı anlamına gelir.

      //--- set yellow color for the source and direct it from above downwards
      m_canvas.LightColorSet(DXColor(1.0,1.0,0.0,0.8f));
      m_canvas.LightDirectionSet(DXVector3(0.0,-1.0,0.0));
      //--- set the blue color for the ambient light 
      m_canvas.AmbientColorSet(DXColor(0.0,0.0,1.0,0.4f));  // must be specified

Aşağıdaki gif animasyonu, ışıklandırma eklediğimizde görüntünün nasıl değiştiğini göstermektedir. Örneğin kaynak kodu Step6 Add Light.mq5 dosyasındadır.

Mavi ortam ışığında sarı ışık kaynağı altında yeşil parıltıya sahip beyaz küp

Mavi ortam ışığında sarı ışık kaynağı altında yeşil parıltıya sahip beyaz küp

Nasıl çalıştığını görmek adına yukarıdaki koddaki renk metotlarını kapatabilirsiniz.


Animasyon

Animasyon, sahne ve nesne parametrelerinde zaman içerisinde değişiklik olmasıdır. Mevcut tüm parametreler zamana/olaylara bağlı olarak değiştirilebilir. Sahnenin güncellenmesini kontrol edecek 10 milisaniyelik bir zamanlayıcı ayarlayalım:

int OnInit()
  {
...
//--- create canvas
   ExtAppWindow=new CCanvas3DWindow();
   if(!ExtAppWindow.Create(width,height))
      return(INIT_FAILED);
//--- set timer
   EventSetMillisecondTimer(10);
//---
   return(INIT_SUCCEEDED);
   }

Zamanlayıcının olayları için CCanvas3DWindow sınıfına nesne parametrelerini (dönme ve hareket) ve ışıklandırma yönünü değiştirecek işleyici ekleyelim:

   //+------------------------------------------------------------------+
   //| Timer handler                                                    |
   //+------------------------------------------------------------------+
   void              OnTimer(void)
     {    
      static ulong last_time=0;
      static float time=0;       
      //--- get the current time
      ulong current_time=GetMicrosecondCount();
      //--- calculate the delta
      float deltatime=(current_time-last_time)/1000000.0f;
      if(deltatime>0.1f)
         deltatime=0.1f;
      //--- increase the elapsed time value
      time+=deltatime;
      //--- remember the time
      last_time=current_time;
      //--- calculate the cube position and the rotation matrix
      DXMatrix rotation,translation,scale;
      DXMatrixRotationYawPitchRoll(rotation,time/11.0f,time/7.0f,time/5.0f);
      DXMatrixTranslation(translation,(float)sin(time/3),0.0,0.0);
      //--- calculate the cube compression/extension along the axes
      DXMatrixScaling(scale,1.0f+0.5f*(float)sin(time/1.3f),1.0f+0.5f*(float)sin(time/1.7f),1.0f+0.5f*(float)sin(time/1.9f));
      //--- multiply the matrices to obtain the final transformation
      DXMatrix transform;
      DXMatrixMultiply(transform,scale,rotation);
      DXMatrixMultiply(transform,transform,translation);
      //--- set the transformation matrix
      m_box.TransformMatrixSet(transform);
      //--- calculate the rotation of the light source around the Z axis
      DXMatrixRotationZ(rotation,deltatime);
      DXVector3 light_direction;
      //--- get the current direction of the light source
      m_canvas.LightDirectionGet(light_direction);
      //--- calculate the new direction of the light source and set it
      DXVec3TransformCoord(light_direction,light_direction,rotation);
      m_canvas.LightDirectionSet(light_direction);
      //--- recalculate the 3D scene and draw it in the canvas
      Redraw();
      }

Lütfen nesne değişikliklerinin ilk değerlerin üzerine yapıldığını unutmayın, yani sanki her zaman küpün ilk durumunu ele alıyormuşuz ve dönme ve hareketle ilgili tüm işlemleri sıfırdan uyguluyormuşuz gibi, bu da küpün mevcut durumunun kaydedilmediği anlamına gelir. Ancak, ışık kaynağının yönü ise mevcut değerden itibaren deltatime artışlarıyla değiştirilir.

Dinamik olarak değişen ışık kaynağı yönüne sahip dönen küp

Dinamik olarak değişen ışık kaynağı yönüne sahip dönen küp

Sonuç olarak, çok karmaşık bir 3D animasyon elde ediyoruz. Örnek kod Step7 Animation.mq5 dosyasındadır.


Fareyle kamera konumunun kontrolü

3D grafiklerdeki son animasyon unsurunu ele alalım: kullanıcı eylemlerine tepki. Örneğimize fareyle kamera konumunu kontrol etme özelliği ekleyelim. Bunu yapmak için fare olaylarını alıyoruz ve uygun işleyicileri oluşturuyoruz:

int OnInit()
  {
...
//--- set the timer
   EventSetMillisecondTimer(10);
//--- enable receiving of mouse events: moving and button clicks
   ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,1);
   ChartSetInteger(0,CHART_EVENT_MOUSE_WHEEL,1)
//---
   return(INIT_SUCCEEDED);
   }
void OnDeinit(const int reason)
  {
//--- Deleting the timer
   EventKillTimer();
//--- disable the receiving of mouse events
   ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,0);
   ChartSetInteger(0,CHART_EVENT_MOUSE_WHEEL,0);
//--- delete the object
   delete ExtAppWindow;
//--- return chart to the usual display mode with price charts
   ChartSetInteger(0,CHART_SHOW,true);
   }
void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
...
//--- chart change event
   if(id==CHARTEVENT_CHART_CHANGE)
      ExtAppWindow.OnChartChange();
//--- mouse movement event
   if(id==CHARTEVENT_MOUSE_MOVE)
      ExtAppWindow.OnMouseMove((int)lparam,(int)dparam,(uint)sparam);
//--- mouse wheel scroll event
   if(id==CHARTEVENT_MOUSE_WHEEL)
      ExtAppWindow.OnMouseWheel(dparam);

Fare hareketi olayları için CCanvas3DWindow sınıfına sol fare tuşuna basılıyken fare hareket ettirildiğinde kamera yönü açılarını değiştirecek işleyici ekleyelim:

   //+------------------------------------------------------------------+
   //| Handle mouse movements                                           |
   //+------------------------------------------------------------------+
   void              OnMouseMove(int x,int y,uint flags)
     {
      //--- left mouse button
      if((flags&1)==1)
        {
         //--- there is no information about the previous mouse position
         if(m_mouse_x!=-1)
           {
            //--- update the camera angle upon change of position
            m_camera_angles.y+=(x-m_mouse_x)/300.0f;
            m_camera_angles.x+=(y-m_mouse_y)/300.0f;
            //--- set the vertical angle in the range between (-Pi/2,Pi2)
            if(m_camera_angles.x<-DX_PI*0.49f)
               m_camera_angles.x=-DX_PI*0.49f;
            if(m_camera_angles.x>DX_PI*0.49f)
               m_camera_angles.x=DX_PI*0.49f;
            //--- update camera position
            UpdateCameraPosition();
            }
         //--- save mouse position
         m_mouse_x=x;
         m_mouse_y=y;
         }
      else
        {
         //--- reset the saved position if the left mouse button is not pressed
         m_mouse_x=-1;
         m_mouse_y=-1;
         }
      }

Ayrıca, fare tekerleği olayları için de kameranın sahnenin merkezine olan mesafesini değiştirecek işleyici ekleyelim:

   //+------------------------------------------------------------------+
   //| Handling mouse wheel events                                      |
   //+------------------------------------------------------------------+
   void              OnMouseWheel(double delta)
     {
      //--- update the distance between the camera and the center upon a mouse scroll
      m_camera_distance*=1.0-delta*0.001;
      //--- set the distance in the range between [3,50]
      if(m_camera_distance>50.0)
         m_camera_distance=50.0;
      if(m_camera_distance<3.0)
         m_camera_distance=3.0;
      //--- update camera position
      UpdateCameraPosition();
      }

Her iki işleyici de güncellenen parametrelere göre kamera konumunu güncellemek için UpdateCameraPosition() metodunu çağırır:

   //+------------------------------------------------------------------+
   //| Updates the camera position                                      |
   //+------------------------------------------------------------------+
   void              UpdateCameraPosition(void)
     {
      //--- the position of the camera taking into account the distance to the center of coordinates
      DXVector4 camera=DXVector4(0.0f,0.0f,-(float)m_camera_distance,1.0f);
      //--- camera rotation around the X axis
      DXMatrix rotation;
      DXMatrixRotationX(rotation,m_camera_angles.x);
      DXVec4Transform(camera,camera,rotation);
      //--- camera rotation around the Y axis
      DXMatrixRotationY(rotation,m_camera_angles.y);
      DXVec4Transform(camera,camera,rotation);
      //--- set camera to position
      m_canvas.ViewPositionSet(DXVector3(camera));
      }

Kaynak kodu Step8 Mouse Control.mq5 dosyasındadır.

Fareyle kamera konumunun kontrolü

Fareyle kamera konumunun kontrolü


Dokular uygulama

Dokular, nesneye materyal, kabartma yanılsaması vermek için çokgen yüzeyine uygulanan bitmap görüntüleridir. Dokular, çokgenler kullanılarak oluşturulması aşırı derecede kaynak gerektirecek tekrarlı küçük yüzey nesnelerinin görünümünü sunmaya olanak tanır. Örneğin bu materyaller taş, ahşap, toprak vb. olabilir.

CDXMesh ve alt sınıfları doku ayarlamaya olanak sağlar. Doku, standart piksel gölgelendiricide DiffuseColor ile birlikte kullanılır. Nesne animasyonunu kaldıralım ve ona bir taş dokusu uygulayalım. Dokular, terminalin çalışma klasörünün MQL5\Files klasöründe bulunmalıdır:

   virtual bool      Create(const int width,const int height)
     {
  ...
      //--- set the white color for the non-directional lighting
      m_box.DiffuseColorSet(DXColor(1.0,1.0,1.0,1.0));

      //--- add texture to draw the cube faces
      m_box.TextureSet(m_canvas.DXDispatcher(),"stone.bmp");
      //--- add the cube to the scene
      m_canvas.ObjectAdd(&m_box);
      //--- redraw the scene
      Redraw();
      //--- succeed
      return(true);
      }

Taş dokulu küp

Taş dokulu küp


Özel nesneler oluşturma

Tüm nesneler köşelerden (DXVector3) oluşur ve köşeler de indekslerle belirli temel öğelere bağlanır. En yaygın temel öğe üçgendir. Basit bir 3D nesne oluşturulması için şunların varlığı gereklidir: köşelerin en azından koordinatlarının (ancak normal, renk vb. gibi birçok ek veri de içerebilir) listesi, köşelerin bağlandıkları temel öğe türü ve temel öğelerin indekslerinin listesi oluşturulması gerekir.


Standart Kütüphane, DXVertex köşe türüne sahiptir: koordinatı, ışıklandırma hesaplaması için normali, doku koordinatlarını ve rengi içerir. Standart köşe gölgelendirici bu köşe türüyle çalışır.

struct DXVertex
  {
   DXVector4         position;  // vertex coordinates
   DXVector4         normal;    // normal vector
   DXVector2         tcoord;    // face coordinate to apply the texture
   DXColor           vcolor;    // color
  };


MQL5\Include\Canvas\DXDXUtils.mqh yardımcı dosyası, temel öğelerin geometrisinin (köşeler ve indeksler) oluşturulması ve obj dosyalarından 3D geometri yüklenmesi için bir dizi metot içerir.

Bir küre ve bir torus oluşturalım ve onlara aynı taş dokusunu uygulayalım:

   virtual bool      Create(const int width,const int height)
     {
 ...     
      // --- vertices and indexes for manually created objects
      DXVertex vertices[];
      uint indices[];
      //--- prepare vertices and indices for the sphere
      if(!DXComputeSphere(0.3f,50,vertices,indices))
         return(false);
      //--- set white color for the vertices
      DXColor white=DXColor(1.0f,1.0f,1.0f,1.0f);
      for(int i=0; i<ArraySize(vertices); i++)
         vertices[i].vcolor=white;
      //--- create the sphere object
      if(!m_sphere.Create(m_canvas.DXDispatcher(),m_canvas.InputScene(),vertices,indices))
        {
         m_canvas.Destroy();
         return(false);
         }
      //--- set diffuse color for the sphere
      m_sphere.DiffuseColorSet(DXColor(0.0,1.0,0.0,1.0));
      //--- set white specular color
      m_sphere.SpecularColorSet(white);
      m_sphere.TextureSet(m_canvas.DXDispatcher(),"stone.bmp");
      //--- add the sphere to a scene
      m_canvas.ObjectAdd(&m_sphere);
      //--- prepare vertices and indices for the torus
      if(!DXComputeTorus(0.3f,0.1f,50,vertices,indices))
         return(false);
      //--- set white color for the vertices
      for(int i=0; i<ArraySize(vertices); i++)
         vertices[i].vcolor=white;
      //--- create the torus object
      if(!m_torus.Create(m_canvas.DXDispatcher(),m_canvas.InputScene(),vertices,indices))
        {
         m_canvas.Destroy();
         return(false);
         }
      //--- set diffuse color for the torus
      m_torus.DiffuseColorSet(DXColor(0.0,0.0,1.0,1.0));
      m_torus.SpecularColorSet(white);
      m_torus.TextureSet(m_canvas.DXDispatcher(),"stone.bmp");
      //--- add the torus to a scene
      m_canvas.ObjectAdd(&m_torus);      
      //--- redraw the scene
      Redraw();
      //--- succeed
      return(true);
      }

Yeni nesneler için animasyon ekleyelim:

   void              OnTimer(void)
     {
...
      m_canvas.LightDirectionSet(light_direction);
      //--- sphere orbit
      DXMatrix translation;
      DXMatrixTranslation(translation,1.1f,0,0);
      DXMatrixRotationY(rotation,time);
      DXMatrix transform;
      DXMatrixMultiply(transform,translation,rotation);
      m_sphere.TransformMatrixSet(transform);
      //--- torus orbit with rotation around its axis
      DXMatrixRotationX(rotation,time*1.3f);
      DXMatrixTranslation(translation,-2,0,0);
      DXMatrixMultiply(transform,rotation,translation);
      DXMatrixRotationY(rotation,time/1.3f);
      DXMatrixMultiply(transform,transform,rotation);
      m_torus.TransformMatrixSet(transform);           
      //--- recalculate the 3D scene and draw it in the canvas
      Redraw();
      }


Değişiklikleri Three Objects.mq5 olarak kaydedelim ve çalıştıralım.

Küpün yörüngesinde dönen şekiller

Küpün yörüngesinde dönen şekiller


Veri tabanlı 3D yüzey

Rapor oluşturmak ve verileri analiz etmek için genellikle çizgi grafikleri, histogramlar, pasta grafikleri vb. gibi çeşitli grafikler kullanılır. MQL5, bu amaçlar için kullanışlı bir grafik kütüphanesi sunmaktadır, ancak bu kütüphane yalnızca 2D grafikler oluşturabilmektedir.

CDXSurface sınıfı, iki boyutlu bir dizide depolanan özel verilerin kullanılarak bir yüzey görselleştirilmesine olanak sağlar. Aşağıdaki matematiksel fonksiyon örneğini görselleştirelim:

z=sin(2.0*pi*sqrt(x*x+y*y))

Yüzeyi çizmek için bir nesne ve verileri depolamak için bir dizi oluşturalım:

   virtual bool      Create(const int width,const int height)
     {
...
      //--- prepare an array to store data
      m_data_width=m_data_height=100;
      ArrayResize(m_data,m_data_width*m_data_height);
      for(int i=0;i<m_data_width*m_data_height;i++)
         m_data[i]=0.0;
      //--- create a surface object
      if(!m_surface.Create(m_canvas.DXDispatcher(),m_canvas.InputScene(),m_data,m_data_width,m_data_height,2.0f,
                           DXVector3(-2.0,-0.5,-2.0),DXVector3(2.0,0.5,2.0),DXVector2(0.25,0.25),
                           CDXSurface::SF_TWO_SIDED|CDXSurface::SF_USE_NORMALS,CDXSurface::CS_COLD_TO_HOT))
        {
         m_canvas.Destroy();
         return(false);
         }
      //--- create texture and reflection
      m_surface.SpecularColorSet(DXColor(1.0,1.0,1.0,1.0));
      m_surface.TextureSet(m_canvas.DXDispatcher(),"checker.bmp");
      //--- add the surface to the scene
      m_canvas.ObjectAdd(&m_surface);
      //--- succeed
      return(true);
      }

Yüzey, tabanı 4x4 ve yüksekliği 1 olan bir kutu içerisinde çizilecektir. Doku boyutları 0,25x0,25'tir.

  • SF_TWO_SIDED, kameranın yüzeyin altına hareket etmesi durumunda yüzeyin hem yukarı hem de aşağı çizileceğini belirtir.
  • SF_USE_NORMALS, yönlü ışık kaynağının neden olduğu yüzeyden yansımaları hesaplamak için normallerin kullanılacağını belirtir.
  • CS_COLD_TO_HOT, yüzeyin ısı haritasını yeşil ve sarı geçişiyle maviden kırmızıya ayarlar.

Yüzeyi canlandırmak için sinüs işaretinin altına zaman ekleyelim ve onu zamanlayıcı ile güncelleyelim.

   void              OnTimer(void)
     {
      static ulong last_time=0;
      static float time=0;
      //--- get the current time
      ulong current_time=GetMicrosecondCount();
      //--- calculate the delta
      float deltatime=(current_time-last_time)/1000000.0f;
      if(deltatime>0.1f)
         deltatime=0.1f;
      //--- increase the elapsed time value
      time+=deltatime;
      //--- remember the time
      last_time=current_time;
      //--- calculate surface values taking into account time changes
      for(int i=0; i<m_data_width; i++)
        {
         double x=2.0*i/m_data_width-1;
         int offset=m_data_height*i;
         for(int j=0; j<m_data_height; j++)
           {
            double y=2.0*j/m_data_height-1;
            m_data[offset+j]=MathSin(2.0*M_PI*sqrt(x*x+y*y)-2*time);
            }
         }
      //--- update data to draw the surface
      if(m_surface.Update(m_data,m_data_width,m_data_height,2.0f,
                          DXVector3(-2.0,-0.5,-2.0),DXVector3(2.0,0.5,2.0),DXVector2(0.25,0.25),
                          CDXSurface::SF_TWO_SIDED|CDXSurface::SF_USE_NORMALS,CDXSurface::CS_COLD_TO_HOT))
        {
         //--- recalculate the 3D scene and draw it in the canvas
         Redraw();
         }
      }

Kaynak kodu 3D Surface.mq5 dosyasındadır. Çalışması aşağıdaki videoda gösterilmektedir:




Bu makalede, görsel veri analizi için basit geometrik şekiller ve animasyonlu 3D grafikler oluşturma konusunda DirectX fonksiyonlarının yeteneklerini ele aldık. MetaTrader 5 terminalinin klasöründen daha karmaşık örnekler bulabilirsiniz: Correlation Matrix 3D ve Math 3D Morpher Uzman Danışmanları ve Remnant 3D komut dosyası. 

MQL5'in yardımıyla, üçüncü taraf paketlere başvurmadan algoritmik ticaretin önemli görevlerini çözebilirsiniz:

  • Çok sayıda girdi parametresi içeren karmaşık ticaret stratejilerini optimize etme
  • Optimizasyon sonuçlarını alma
  • Alınan verileri en uygun üç boyutlu grafikte görselleştirme
MetaTrader 5'te hisse verilerini görselleştirmek ve ticaret stratejileri geliştirmek için tüm yetenekleri kullanın - şimdi 3D grafiklerle!


MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/7708

Ekli dosyalar |
Step4_Box_Color.mq5 (15.25 KB)
Step6_Add_Light.mq5 (14.27 KB)
Step7_Animation.mq5 (18.83 KB)
Step9_Texture.mq5 (23.16 KB)
Three_Objects.mq5 (27.9 KB)
3D_Surface.mq5 (24.48 KB)
MQL5.zip (199.48 KB)
Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 10): Özel göstergelere erişim Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 10): Özel göstergelere erişim
Doğrudan Uzman Danışmandan özel göstergelere nasıl erişilir? Bir ticaret Uzman Danışmanı yalnızca özel göstergeler kullanabiliyorsa gerçek anlamda yararlı olabilir, aksi takdirde sadece bir dizi kod parçası olacaktır.
Görselleştirin! R dilinin plot fonksiyonuna benzer MQL5 grafik kütüphanesi Görselleştirin! R dilinin plot fonksiyonuna benzer MQL5 grafik kütüphanesi
Ticaret modellerini incelerken grafikler şeklinde görselleştirme büyük önem taşımaktadır. R ve Python gibi bilim topluluğu arasında popüler olan programlama dilleri görselleştirme için özel plot fonksiyonuna sahiptir. Bu fonksiyon, ticaret modellerinin çizgiler, nokta dağılımları ve histogramlar şeklinde görselleştirilmesine olanak sağlar. MQL5’te de aynısı CGraphics sınıfı kullanılarak yapılabilir.
Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 11): Çapraz emir sistemi Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 11): Çapraz emir sistemi
Bu makalede çapraz emir sistemi oluşturacağız. Yatırımcıların hayatını çok zorlaştıran bir varlık türü vardır - vadeliler. Peki neden hayatı zorlaştırıyorlar?
SQLite: MQL5'te SQL veritabanlarıyla yerel olarak çalışma SQLite: MQL5'te SQL veritabanlarıyla yerel olarak çalışma
Ticaret stratejilerinin geliştirilmesi, büyük miktarda verinin işlenmesiyle ilişkilidir. Artık doğrudan MQL5'te SQLite tabanlı SQL sorguları kullanarak veritabanlarıyla çalışabilirsiniz. Bu motorun önemli bir avantajı, tüm veritabanının kullanıcının bilgisayarında bulunan tek bir dosyaya yerleştirilmiş olmasıdır.