English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Önceden tanımlanmış risk ve R/R oranına dayalı etkileşimli yarı otomatik sürükle ve bırak Uzman Danışman (EA) oluşturma

Önceden tanımlanmış risk ve R/R oranına dayalı etkileşimli yarı otomatik sürükle ve bırak Uzman Danışman (EA) oluşturma

MetaTrader 5Örnekler | 16 Aralık 2021, 14:11
142 0
investeo
investeo

Giriş

Bazı yatırımcılar tüm alım-satımları otomatik olarak yürütür ve bazıları birkaç göstergenin çıkışına bağlı olarak otomatik ve manuel alım-satımları karıştırır. Sonraki grubun bir üyesi olarak risk ve ödül seviyelerini doğrudan grafikten dinamik olarak değerlendirmek için etkileşimli bir araca ihtiyacım vardı.

Hisse senedim üzerinde maksimum risk beyan ederek zararı durdur seviyesine bağlı olarak gerçek zamanlı parametreleri hesaplamak istedim, grafiği açtım ve hesaplanan SL ve TP seviyelerine bağlı olarak alım satımımı doğrudan EA’dan yürütmem gerekti.

Bu makale, önceden tanımlanmış hisse senedi riski ve R/R oranı ile etkileşimli yarı otomatik bir Uzman Danışman (EA) uygulamanın bir yolunu sunacaktır. Uzman Danışman (EA) riski, RR ve lot boyutu parametreleri EA paneli üzerinde çalışma süresi boyunca değiştirilebilir. 


1. Gereklilikler

EA için gereklilikler aşağıdaki gibiydi:

  • başlangıçta risk seviyesini önceden tanımlama ve pozisyon boyutunu nasıl etkilediğini görmek için çalışma zamanı sırasında değiştirme olanağı
  • risk/ödül oranını önceden tanımlama ve bunu çalışma zamanı sırasında değiştirme olanağı
  • belirli risk ve zararı durdur seviyesi için gerçek zamanlı maksimum lot boyutunu hesaplama olanağı
  • hisse senedi riski ve ödülünü nasıl etkilediğini görmek için çalışma zamanında lot boyutunu değiştirme olanağı
  • doğrudan EA’dan piyasa alış/satış emri yürütme olanağı
  • zararı durdur değerini ayarlamak ve önceden tanımlı risk/ödül seviyesi için fiyat seviyesini görmek için sürükle ve bırak arayüzü 


2. Tasarım

Çalışma zamanı sırasında parametreleri görüntüleme ve değiştirme EA gereklilikleri nedeniyle, grafik penceresinde GUI'yi görüntülemek ve gelen grafik olaylarını kullanıcı etkileşimi için işlemek için CChartObject sınıflarını ve bunun soyundan gelenleri kullanmaya karar verdim. Bu nedenle, EA etiketler, düğmeler ve düzenleme alanları ile kullanıcı arayüzü gerektirdi.

Başlangıçta paneldeki diğer nesneleri gruplamak için CChartObjectPanel nesnesini kullanmak istedim ama farklı bir yaklaşım denemeye karar verdim, etiketleri tutan, alanları ve düğmeleri düzenleyen ve bunu bir görüntü arka planında görüntüleyen bir sınıf tasarladım. Arayüzün arka plan görüntüsü GIMP yazılımı kullanılarak oluşturuldu. MQL5 ile oluşturulan nesneler düzenleme alanları, gerçek zamanlı güncellenen kırmızı etiketler ve düğmelerdir.

Ben sadece etiket nesnelerini grafiğe koydum ve konumlarını kaydettim ve hesaplanan çıkışı görüntüleme, CChartObjectEdit alanlarının parametrelerini alma ve düğme durumlarını kaydetme işlevlerini yerine getiren CRRDialog sınıfını oluşturdum. Renkli risk ve ödül dikdörtgenleri CChartObjectRectangle sınıfının nesneleridir ve sürüklenebilir zararı durdur işaretçisi CChartObjectBitmap sınıfının bir bitmap nesnesidir.


 

Şekil 1. Görsel EA ekran görüntüsü

Şekil 1. Görsel EA ekran görüntüsü

 


3. EA iletişim kutusu sınıfının yorumlanması

CRRDialog sınıfı, EA’nın tüm kullanıcı arayüzünü ele alır. Görüntülenen bir dizi değişkeni, değişkenleri görüntülemek için kullanılan nesneleri ve değişken değerlerini almak/ayarlamak ve iletişim kutusunu yenilemek için kullanılan yöntemleri içerir.

Arka plan için CChartObjectBmpLabel nesnesini, düzenleme alanları için CChartObjectEdit nesnelerini, etiketleri görüntülemek için CChartObjectLabel nesnelerini ve düğmeler için CChartObjectButton nesnelerini kullanıyorum: 

class CRRDialog
  {
private:

   int               m_baseX;
   int               m_baseY;
   int               m_fontSize;
   
   string            m_font;
   string            m_dialogName;
   string            m_bgFileName;

   double            m_RRRatio;
   double            m_riskPercent;
   double            m_orderLots;
   double            m_SL;
   double            m_TP;
   double            m_maxAllowedLots;
   double            m_maxTicksLoss;
   double            m_orderEquityRisk;
   double            m_orderEquityReward;
   ENUM_ORDER_TYPE   m_orderType;

   CChartObjectBmpLabel m_bgDialog;

   CChartObjectEdit  m_riskRatioEdit;
   CChartObjectEdit  m_riskValueEdit;
   CChartObjectEdit  m_orderLotsEdit;

   CChartObjectLabel m_symbolNameLabel;
   CChartObjectLabel m_tickSizeLabel;
   CChartObjectLabel m_maxEquityLossLabel;
   CChartObjectLabel m_equityLabel;
   CChartObjectLabel m_profitValueLabel;
   CChartObjectLabel m_askLabel;
   CChartObjectLabel m_bidLabel;
   CChartObjectLabel m_tpLabel;
   CChartObjectLabel m_slLabel;
   CChartObjectLabel m_maxAllowedLotsLabel;
   CChartObjectLabel m_maxTicksLossLabel;
   CChartObjectLabel m_orderEquityRiskLabel;
   CChartObjectLabel m_orderEquityRewardLabel;
   CChartObjectLabel m_orderTypeLabel;

   CChartObjectButton m_switchOrderTypeButton;
   CChartObjectButton m_placeOrderButton;
   CChartObjectButton m_quitEAButton;

public:

   void              CRRDialog(); // CRRDialog constructor
   void             ~CRRDialog(); // CRRDialog destructor

   bool              CreateCRRDialog(int topX,int leftY);
   int               DeleteCRRDialog();
   void              Refresh();
   void              SetRRRatio(double RRRatio);
   void              SetRiskPercent(double riskPercent);
   double            GetRiskPercent();
   double            GetRRRRatio();
   void              SetSL(double sl);
   void              SetTP(double tp);
   double            GetSL();
   double            GetTP();
   void              SetMaxAllowedLots(double lots);
   void              SetMaxTicksLoss(double ticks);
   void              SetOrderType(ENUM_ORDER_TYPE);
   void              SwitchOrderType();
   void              ResetButtons();
   ENUM_ORDER_TYPE   GetOrderType();
   void              SetOrderLots(double orderLots);
   double            GetOrderLots();
   void              SetOrderEquityRisk(double equityRisk);
   void              SetOrderEquityReward(double equityReward);
  };

Değişkenleri alma/ayarlama yöntemleri basit olduğundan CreateCRRDialog() ve Refresh() yöntemlerine odaklanacağım. CreateCRRDialog() yöntemi arka plan görüntüsünü, etiketleri, düğmeleri ve düzenleme alanlarını başlatır.

Etiketleri ve düzenleme alanlarını başlatmak için şunları kullanıyorum: Grafik üzerinde nesneyi konumlandırmak için koordinat parametreleri ile Create() yöntemi, yazı tipini ayarlamak için FontSize() yöntemi ve etiket üzerine metin koymak için Description() yöntemi.

Düğmeler için: Create() yöntemi ek parametreleri düğme boyutunu belirtir ve  BackColor() yöntemi düğmenin arka plan rengini belirtir. 

bool CRRDialog::CreateCRRDialog(int topX,int leftY)
  {
   bool isCreated=false;

   MqlTick current_tick;
   SymbolInfoTick(Symbol(),current_tick);

   m_baseX = topX;
   m_baseY = leftY;

   m_bgDialog.Create(0, m_dialogName, 0, topX, leftY);
   m_bgDialog.BmpFileOn(m_bgFileName);

   m_symbolNameLabel.Create(0, "symbolNameLabel", 0, m_baseX + 120, m_baseY + 40);
   m_symbolNameLabel.Font("Verdana");
   m_symbolNameLabel.FontSize(8);
   m_symbolNameLabel.Description(Symbol());

   m_tickSizeLabel.Create(0, "tickSizeLabel", 0, m_baseX + 120, m_baseY + 57);
   m_tickSizeLabel.Font("Verdana");
   m_tickSizeLabel.FontSize(8);
   m_tickSizeLabel.Description(DoubleToString(SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_SIZE), Digits()));

   m_riskRatioEdit.Create(0, "riskRatioEdit", 0, m_baseX + 120, m_baseY + 72, 35, 15);
   m_riskRatioEdit.Font("Verdana");
   m_riskRatioEdit.FontSize(8);
   m_riskRatioEdit.Description(DoubleToString(m_RRRatio, 2));

   m_riskValueEdit.Create(0, "riskValueEdit", 0, m_baseX + 120, m_baseY + 90, 35, 15);
   m_riskValueEdit.Font("Verdana");
   m_riskValueEdit.FontSize(8);
   m_riskValueEdit.Description(DoubleToString(m_riskPercent, 2));

   m_equityLabel.Create(0, "equityLabel", 0, m_baseX + 120, m_baseY + 107);
   m_equityLabel.Font("Verdana");
   m_equityLabel.FontSize(8);
   m_equityLabel.Description(DoubleToString(AccountInfoDouble(ACCOUNT_EQUITY),2));

   m_maxEquityLossLabel.Create(0, "maxEquityLossLabel", 0, m_baseX + 120, m_baseY + 122);
   m_maxEquityLossLabel.Font("Verdana");
   m_maxEquityLossLabel.FontSize(8);
   m_maxEquityLossLabel.Description(DoubleToString(AccountInfoDouble(ACCOUNT_EQUITY)*m_riskPercent/100.0,2));

   m_askLabel.Create(0, "askLabel", 0, m_baseX + 120, m_baseY + 145);
   m_askLabel.Font("Verdana");
   m_askLabel.FontSize(8);
   m_askLabel.Description("");

   m_bidLabel.Create(0, "bidLabel", 0, m_baseX + 120, m_baseY + 160);
   m_bidLabel.Font("Verdana");
   m_bidLabel.FontSize(8);
   m_bidLabel.Description("");

   m_slLabel.Create(0, "slLabel", 0, m_baseX + 120, m_baseY + 176);
   m_slLabel.Font("Verdana");
   m_slLabel.FontSize(8);
   m_slLabel.Description("");

   m_tpLabel.Create(0, "tpLabel", 0, m_baseX + 120, m_baseY + 191);
   m_tpLabel.Font("Verdana");
   m_tpLabel.FontSize(8);
   m_tpLabel.Description("");

   m_maxAllowedLotsLabel.Create(0, "maxAllowedLotsLabel", 0, m_baseX + 120, m_baseY + 208);
   m_maxAllowedLotsLabel.Font("Verdana");
   m_maxAllowedLotsLabel.FontSize(8);
   m_maxAllowedLotsLabel.Description("");

   m_maxTicksLossLabel.Create(0, "maxTicksLossLabel", 0, m_baseX + 120, m_baseY + 223);
   m_maxTicksLossLabel.Font("Verdana");
   m_maxTicksLossLabel.FontSize(8);
   m_maxTicksLossLabel.Description("");

   m_orderLotsEdit.Create(0, "orderLotsEdit", 0, m_baseX + 120, m_baseY + 238, 35, 15);
   m_orderLotsEdit.Font("Verdana");
   m_orderLotsEdit.FontSize(8);
   m_orderLotsEdit.Description("");

   m_orderEquityRiskLabel.Create(0, "orderEquityRiskLabel", 0, m_baseX + 120, m_baseY + 255);
   m_orderEquityRiskLabel.Font("Verdana");
   m_orderEquityRiskLabel.FontSize(8);
   m_orderEquityRiskLabel.Description("");

   m_orderEquityRewardLabel.Create(0, "orderEquityRewardLabel", 0, m_baseX + 120, m_baseY + 270);
   m_orderEquityRewardLabel.Font("Verdana");
   m_orderEquityRewardLabel.FontSize(8);
   m_orderEquityRewardLabel.Description("");

   m_switchOrderTypeButton.Create(0, "switchOrderTypeButton", 0, m_baseX + 20, m_baseY + 314, 160, 20);
   m_switchOrderTypeButton.Font("Verdana");
   m_switchOrderTypeButton.FontSize(8);
   m_switchOrderTypeButton.BackColor(LightBlue);

   m_placeOrderButton.Create(0, "placeOrderButton", 0, m_baseX + 20, m_baseY + 334, 160, 20);
   m_placeOrderButton.Font("Verdana");
   m_placeOrderButton.FontSize(8);
   m_placeOrderButton.BackColor(LightBlue);
   m_placeOrderButton.Description("Place Market Order");

   m_quitEAButton.Create(0, "quitEAButton", 0, m_baseX + 20, m_baseY + 354, 160, 20);
   m_quitEAButton.Font("Verdana");
   m_quitEAButton.FontSize(8);
   m_quitEAButton.BackColor(LightBlue);
   m_quitEAButton.Description("Quit");

   return isCreated;
  }

Refresh() yöntemi, tüm etiketlerin ve düğmelerin açıklamasını CRRDialog değişkenleri ve mevcut alış/satış seviyeler, hesap hisse senedi ve hisse senedi risk değerleri ile yeniler: 

void CRRDialog::Refresh()
  {
   MqlTick current_tick;
   SymbolInfoTick(Symbol(),current_tick);

   m_equityLabel.Description(DoubleToString(AccountInfoDouble(ACCOUNT_EQUITY),2));
   m_maxEquityLossLabel.Description(DoubleToString(AccountInfoDouble(ACCOUNT_EQUITY)*
                                         StringToDouble(m_riskValueEdit.Description())/100.0,2));
   m_askLabel.Description(DoubleToString(current_tick.ask, Digits()));
   m_bidLabel.Description(DoubleToString(current_tick.bid, Digits()));
   m_slLabel.Description(DoubleToString(m_SL, Digits()));
   m_tpLabel.Description(DoubleToString(m_TP, Digits()));
   m_maxAllowedLotsLabel.Description(DoubleToString(m_maxAllowedLots,2));
   m_maxTicksLossLabel.Description(DoubleToString(m_maxTicksLoss,0));
   m_orderEquityRiskLabel.Description(DoubleToString(m_orderEquityRisk,2));
   m_orderEquityRewardLabel.Description(DoubleToString(m_orderEquityReward,2));

   if(m_orderType==ORDER_TYPE_BUY) m_switchOrderTypeButton.Description("Order Type: BUY");
   else if(m_orderType==ORDER_TYPE_SELL) m_switchOrderTypeButton.Description("Order Type: SELL");
  }


4. Grafik Etkinlikleri

EA etkileşimli olmak üzere tasarlandığı için grafik etkinliklerini ele alacaktır.

Ele alınan etkinlikler şunları içerir:

  • grafik üzerinde S/L işaretçisinin (CChartObjectBitmap sınıfının SL_arrow nesnesi) sürüklenmesi - bu S/L seviyesini toplamayı ve R/R oranına bağlı olarak T/P seviyesini hesaplamayı sağlayacaktır
  • emir türü (alış/satış) düğmesine basılması
  • ‘piyasa emri oluştur’ düğmesine basılması
  • risk, R/R ve emir lotu alanlarının düzenlenmesi
  • ‘Çıkış’ düğmesine basıldıktan sonra EA’nın kapatılması

Ele alınan etkinlikler şunlardır: işaretçi seçimi ve düğmeler için CHARTEVENT_OBJECT_CLICK , S/L işaretçisini sürüklemek için CHARTEVENT_OBJECT_DRAG ve düzenleme alanları yatırımcı tarafından düzenlendikten sonra CHARTEVENT_OBJECT_ENDEDIT.

OnChartEvent() fonksiyonunun birinci uygulaması birkaç kod sayfası sürdü, fakat bunu birkaç etkinlik işleyiciye ayırmaya karar verdim, bu OnChartEvent() fonksiyonunu insan tarafından okunabilir forma dönüştürdü: 

void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Check the event by pressing a mouse button
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      string clickedChartObject=sparam;

      if(clickedChartObject==slButtonID)
         SL_arrow.Selected(!SL_arrow.Selected());

      if(clickedChartObject==switchOrderTypeButtonID)
        {
         EA_switchOrderType();
        };

      if(clickedChartObject==placeOrderButtonID)
        {
         EA_placeOrder();
        }

      if(clickedChartObject==quitEAButtonID) ExpertRemove();

      ChartRedraw();
     }

   if(id==CHARTEVENT_OBJECT_DRAG)
     {
      // BUY 
      if(visualRRDialog.GetOrderType()==ORDER_TYPE_BUY)
        {
         EA_dragBuyHandle();
        };

      // SELL
      if(visualRRDialog.GetOrderType()==ORDER_TYPE_SELL)
        {
         EA_dragSellHandle();
        };
      ChartRedraw();
     }

   if(id==CHARTEVENT_OBJECT_ENDEDIT)
     {
      if((sparam==riskRatioEditID || sparam==riskValueEditID || sparam==orderLotsEditID) && orderPlaced==false)
        {
         EA_editParamsUpdate();
        }
     }
  }

Etkinlik işleyicilerinin uygulanması sonraki bölümlerde daha ayrıntılı açıklanacaktır. SL_arrow nesnesini seçmek için kullandığım püf noktası kayda değerdir. Normalde, grafik üzerinde bir nesneyi seçmek için üzerine iki kez tıklamak gerekir. Fakat bu bir kez tıklayarak ve CHARTEVENT_OBJECT_CLICK etkinlik işleyicisi içerisinde OnChartEvent() içinde CChartObject nesnesinin veya bunun soyundan gelen Selected() yönteminin uygulanması yoluyla seçilebilir:

      if(clickedChartObject==slButtonID)
         SL_arrow.Selected(!SL_arrow.Selected());

Nesne bir kez tıkladıktan sonra önceki duruma bağlı olarak seçilir veya seçimi kaldırılır. 


5. CMoneyFixedRisk’e dayalı Genişletilmiş Para Yönetimi sınıfı

ChartEvent işleyicilerini açıklamadan önce para yönetimi sınıfının üzerinden geçmem gerek.

Para yönetimi için MetaQuotes tarafından sağlanan CMoneyFixedRisk sınıfını yeniden kullandım ve CMoneyFixedRiskExt sınıfını uyguladım.

Orijinal CMoneyFixedRisk sınıfı yöntemler, verilen fiyat için izin verilen emir lotu miktarlarını, zararı durdur seviyesini ve aracı tarafından izin verilen minimum ve maksimum lot boyutu arasında hisse senedi riskini döndürür. Risk gereklilikleri karşılanmazsa 0,0 lot boyutuna dönmek için CheckOpenLong() ve CheckOpenShort() yöntemlerini değiştirdim ve bunu dört yöntemle genişlettim: GetMaxSLPossible(), CalcMaxTicksLoss(), CalcOrderEquityRisk() ve CalcOrderEquityReward():

class CMoneyFixedRiskExt : public CExpertMoney
  {
public:
   //---
   virtual double    CheckOpenLong(double price,double sl);
   virtual double    CheckOpenShort(double price,double sl);
   
   double GetMaxSLPossible(double price, ENUM_ORDER_TYPE orderType);
   double CalcMaxTicksLoss();
   double CalcOrderEquityRisk(double price, double sl, double lots);
   double CalcOrderEquityReward(double price, double sl, double lots, double rrratio);
  };

GetMaxSLPossible() yöntemi, belirli hisse senedi riski için maksimum zararı durdur fiyat değerini ve izin verilen minimum alım satım boyutunu hesaplar.

Örneğin, hesap bakiyesi hesap temel para biriminde 10.000 ise ve risk %2’yse hesap para biriminde maksimum 200’ü riske edebiliriz. Minimum alım satım lot boyutu 0,1 lot ise bu yöntem, 0,1 lotunun konumu için hisse senedi riskinin değerini karşılayacak olan ORDER_TYPE_BUY veya ORDER_TYPE_SELL emri için fiyat seviyesine döndürür. Bu, minimum lot boyutu alım satımı için göze alabileceğimiz maksimum zararı durdur seviyesini tahmin etmeye yardımcı olur. Bu, verilen hisse senedi risk seviyesi için aşamayacağımız fiyat seviyesidir. 

double CMoneyFixedRiskExt::GetMaxSLPossible(double price, ENUM_ORDER_TYPE orderType)
{
   double maxEquityLoss, tickValLoss, maxTicksLoss;
   double minvol=m_symbol.LotsMin();
   double orderTypeMultiplier;
   
   if(m_symbol==NULL) return(0.0);
   
   switch (orderType)
   {
   case ORDER_TYPE_SELL: orderTypeMultiplier = -1.0; break;
   case ORDER_TYPE_BUY: orderTypeMultiplier = 1.0; break;
   default: orderTypeMultiplier = 0.0;
   }
   
   maxEquityLoss = m_account.Balance()*m_percent/100.0; // max loss 
   tickValLoss = minvol*m_symbol.TickValueLoss(); // tick val loss
   maxTicksLoss = MathFloor(maxEquityLoss/tickValLoss);
 
   return (price - maxTicksLoss*m_symbol.TickSize()*orderTypeMultiplier);
}

CalcMaxTickLoss() yöntemi, verilen risk ve izin verilen minimum lot boyutu için kaybetmeyi göze alabileceğimiz maksimum tik sayısına döndürür.

Başlangıçta, maksimum hisse senedi kaybı mevcut bakiyenin yüzdesi olarak hesaplanır, ardından verilen sembol için izin verilen minimum lot boyutu için bir tik değişikliği için tik değeri kaybı hesaplanır. Ardından maksimum hisse senedi kaybı tik değeri kaybına bölünür ve sonuç MathFloor() fonksiyonu ile tamsayı değerine yuvarlanır:

double CMoneyFixedRiskExt::CalcMaxTicksLoss()
{
   double maxEquityLoss, tickValLoss, maxTicksLoss;
   double minvol=m_symbol.LotsMin();
   
   if(m_symbol==NULL) return(0.0);
   
   maxEquityLoss = m_account.Balance()*m_percent/100.0; // max loss 
   tickValLoss = minvol*m_symbol.TickValueLoss(); // tick val loss
   maxTicksLoss = MathFloor(maxEquityLoss/tickValLoss);
   
   return (maxTicksLoss);
}

CalcOrderEquityRisk() yöntemi, verilen fiyat için hisse senedi riskini, zararı durdur seviyesini ve lotların miktarlarını döndürür. Bu, tik kaybı değerinin lotların sayısı ve fiyat ile çarpılması, ardından mevcut fiyat ve zararı durdur seviyesi arasındaki farkla çarpılması yoluyla hesaplanır:

double CMoneyFixedRiskExt::CalcOrderEquityRisk(double price,double sl, double lots)
{
   double equityRisk;
   
   equityRisk = lots*m_symbol.TickValueLoss()*(MathAbs(price-sl)/m_symbol.TickSize()); 
   
   if (dbg) Print("calcEquityRisk: lots = " + DoubleToString(lots) +
                 " TickValueLoss = " + DoubleToString(m_symbol.TickValueLoss()) +
                 " risk = " + DoubleToString(equityRisk));
   
   return equityRisk;
}

 CalcOrderEquityReward() yöntemi, CalcOrderEquityRisk() yöntemine benzer, fakat TickValueLoss() yöntemi yerine TickValueProfit() kullanır ve sonuç verilen risk/ödül oranı ile çarpılır:  

double CMoneyFixedRiskExt::CalcOrderEquityReward(double price,double sl, double lots, double rrratio)
{
   double equityReward; 
   equityReward = lots*m_symbol.TickValueProfit()*(MathAbs(price-sl)/m_symbol.TickSize())*rrratio; 
   
   if (dbg) Print("calcEquityReward: lots = " + DoubleToString(lots) + 
                   " TickValueProfit = " + DoubleToString(m_symbol.TickValueProfit()) +
                 " reward = " + DoubleToString(equityReward));
   return equityReward;
}

Bu yöntemler, maksimum zararı durdur seviyelerini hesaplamak ve gerçek zamanlı hisse senedi riski ve ödülünü döndürmek için yeterlidir. CalcMaxTickLoss() yöntemi, risk dikdörtgeninin çizimini düzeltmek için kullanılır - yatırımcı kaybetmeyi göze alabileceği tik sayısı sınırını aşan bir alım satım yapmak isterse dikdörtgen sadece kaybedebileceği maksimum tik sayısına çizilir.

Bunu doğrudan grafik üzerinde görmek hayatı kolaylaştırır. Bunu makalenin sonundaki demoda görebilirsiniz.


6. Grafik Etkinliği işleyicilerini uygulama

EA_switchOrderType() işleyicisi, m_switchOrderTypeButton nesnesi üzerinde CHARTEVENT_OBJECT_CLICK etkinliği alındıktan sonra tetiklenir. Emir türünü ORDER_TYPE_BUY ve ORDER_TYPE_SELL arasında değiştirir, düğmelerin durumunu, iletişim kutusunun değişkenlerini sıfırlar ve grafikteki risk ve ödül dikdörtgeni nesnelerini siler:

void EA_switchOrderType()
  {
   symbolInfo.RefreshRates();

   visualRRDialog.SwitchOrderType();
   visualRRDialog.ResetButtons();
   visualRRDialog.SetSL(0.0);
   visualRRDialog.SetTP(0.0);
   visualRRDialog.SetMaxAllowedLots(0.0);
   visualRRDialog.SetOrderLots(0.0);
   visualRRDialog.SetMaxTicksLoss(0);
   visualRRDialog.SetOrderEquityRisk(0.0);
   visualRRDialog.SetOrderEquityReward(0.0);

   if(visualRRDialog.GetOrderType()==ORDER_TYPE_BUY) SL_arrow.SetDouble(OBJPROP_PRICE,symbolInfo.Ask());
   else if(visualRRDialog.GetOrderType()==ORDER_TYPE_SELL) SL_arrow.SetDouble(OBJPROP_PRICE,symbolInfo.Bid());
   SL_arrow.SetInteger(OBJPROP_TIME,0,TimeCurrent());

   rectReward.Delete();
   rectRisk.Delete();

   visualRRDialog.Refresh();

  }

EA_dragBuyHandle() işleyicisi, grafik üzerinde SL_arrow nesnesi sürüklenip bırakıldıktan sonra tetiklenir. Başlangıçta, grafikten SL_arrow nesnesi sürükleme noktası zamanını ve fiyat parametrelerini okur ve alım satımımız için varsayımsal zararı durdur olarak fiyat seviyesini ayarlar.

Ardından, hisse senedi üzerinde verilen risk için kaç tane lot açabileceğimizi hesaplar. Zararı durdur değeri bu sembol üzerinde olası en düşük alım satım lotu için risk hedefini garanti edemezse, bu otomatik olarak olası maksimum SL seviyesine taşınır. Bu, verilen risk için zararı durdur için ne kadar alana sahip olduğumuzu değerlendirmeye yardımcı olur.

Risk ve ödülü hesapladıktan sonra, dikdörtgen hedefleri grafikte güncellenir.

void EA_dragBuyHandle()
  {
   SL_arrow.GetDouble(OBJPROP_PRICE,0,SL_price);
   SL_arrow.GetInteger(OBJPROP_TIME,0,startTime);

   symbolInfo.RefreshRates();
   currentTime=TimeCurrent();

// BUY
   double allowedLots=MM.CheckOpenLong(symbolInfo.Ask(),SL_price);
   Print("Allowed lots = "+DoubleToString(allowedLots,2));
   double lowestSLAllowed=MM.GetMaxSLPossible(symbolInfo.Ask(),ORDER_TYPE_BUY);

   if(SL_price<lowestSLAllowed)
     {
      SL_price=lowestSLAllowed;
      ObjectSetDouble(0,slButtonID,OBJPROP_PRICE,lowestSLAllowed);
     }

   visualRRDialog.SetSL(SL_price);
   visualRRDialog.SetTP(symbolInfo.Ask()+(symbolInfo.Ask()-SL_price)*visualRRDialog.GetRRRRatio());

   if(visualRRDialog.GetTP()<SL_price)
     {
      visualRRDialog.SetSL(0.0);
      visualRRDialog.SetTP(0.0);
      SL_arrow.SetDouble(OBJPROP_PRICE,symbolInfo.Ask());
      rectReward.Delete();
      rectRisk.Delete();
      return;
     }

   double lotSize=MM.CheckOpenLong(symbolInfo.Ask(),SL_price);

   visualRRDialog.SetMaxAllowedLots(lotSize);
   visualRRDialog.SetOrderLots(lotSize);
   visualRRDialog.SetMaxTicksLoss(MM.CalcMaxTicksLoss());
   visualRRDialog.SetOrderEquityRisk(MM.CalcOrderEquityRisk(symbolInfo.Ask(), SL_price, lotSize));
   visualRRDialog.SetOrderEquityReward(MM.CalcOrderEquityReward(symbolInfo.Ask(), 
                                       SL_price, lotSize, visualRRDialog.GetRRRRatio()));
   visualRRDialog.Refresh();

   rectUpdate(visualRRDialog.GetOrderType());

  }

EA_dragSellHandle(), satış emri yapılandırması için tetiklenir.

Hesaplamalar symbolInfo.Bid() fiyatına dayalıdır ve dikdörtgenler uygun olarak çizilir, yani, yeşil bölge işaretleme karı, mevcut fiyat seviyesinin altındadır.. 

void EA_dragSellHandle()
  {
   SL_arrow.GetDouble(OBJPROP_PRICE,0,SL_price);
   SL_arrow.GetInteger(OBJPROP_TIME,0,startTime);

   symbolInfo.RefreshRates();
   currentTime=TimeCurrent();

   double allowedLots=MM.CheckOpenShort(symbolInfo.Bid(),SL_price);
   Print("Allowed lots = "+DoubleToString(allowedLots,2));
   double maxSLAllowed=MM.GetMaxSLPossible(symbolInfo.Bid(),ORDER_TYPE_SELL);

   if(SL_price>maxSLAllowed)
     {
      SL_price=maxSLAllowed;
      SL_arrow.SetDouble(OBJPROP_PRICE,0,maxSLAllowed);
     }

   visualRRDialog.SetSL(SL_price);
   visualRRDialog.SetTP(symbolInfo.Bid()-(SL_price-symbolInfo.Bid())*visualRRDialog.GetRRRRatio());

   if(visualRRDialog.GetTP()>SL_price)
     {
      visualRRDialog.SetSL(0.0);
      visualRRDialog.SetTP(0.0);
      SL_arrow.SetDouble(OBJPROP_PRICE,symbolInfo.Bid());
      rectReward.Delete();
      rectRisk.Delete();
      return;
     }

   double lotSize=MM.CheckOpenShort(symbolInfo.Bid(),SL_price);

   visualRRDialog.SetMaxAllowedLots(lotSize);
   visualRRDialog.SetOrderLots(lotSize);
   visualRRDialog.SetMaxTicksLoss(MM.CalcMaxTicksLoss());
   visualRRDialog.SetOrderEquityRisk(MM.CalcOrderEquityRisk(symbolInfo.Bid(), SL_price, lotSize));
   visualRRDialog.SetOrderEquityReward(MM.CalcOrderEquityReward(symbolInfo.Bid(),
                                       SL_price, lotSize, visualRRDialog.GetRRRRatio()));
   visualRRDialog.Refresh();

   rectUpdate(visualRRDialog.GetOrderType());

  }

EA_placeOrder(), m_placeOrderButton nesnesine basıldıktan sonra tetiklenir. Hesaplanan SL ve TP seviyeleri ve verilen lot boyutu için alış veya satış piyasa emri verir.

CExpertTrade sınıfını kullanarak piyasa emri oluşturmanın ne kadar kolay olduğuna lütfen dikkat edin. 

bool EA_placeOrder()
  {
   symbolInfo.RefreshRates();
   visualRRDialog.ResetButtons();

   if(visualRRDialog.GetOrderType()==ORDER_TYPE_BUY)
      orderPlaced=trade.Buy(visualRRDialog.GetOrderLots(),symbolInfo.Ask(),
                            visualRRDialog.GetSL(),visualRRDialog.GetTP(),TimeToString(TimeCurrent()));
   else if(visualRRDialog.GetOrderType()==ORDER_TYPE_SELL)
      orderPlaced=trade.Sell(visualRRDialog.GetOrderLots(),symbolInfo.Bid(),
                            visualRRDialog.GetSL(),visualRRDialog.GetTP(),TimeToString(TimeCurrent()));

   return orderPlaced;
  }

EA_editParamsUpdate() işleyicisi, şu düzenleme alanlarından biri düzenlendikten sonra Enter tuşuna basıldığında tetiklenir: riskRatioEdit, riskValueEdit ve orderLotsEdit.

Bu meydana geldiğinde izin verilen lot boyutunun, TP seviyesinin, maks. tik kaybının, hisse senedi riski ve ödülünün yeniden hesaplanması gerekir:

void EA_editParamsUpdate()
  {
   MM.Percent(visualRRDialog.GetRiskPercent());

   SL_arrow.GetDouble(OBJPROP_PRICE, 0, SL_price);
   SL_arrow.GetInteger(OBJPROP_TIME, 0, startTime);

   symbolInfo.RefreshRates();
   currentTime=TimeCurrent();

   double allowedLots=MM.CheckOpenLong(symbolInfo.Ask(),SL_price);

   double lowestSLAllowed=MM.GetMaxSLPossible(symbolInfo.Ask(),ORDER_TYPE_BUY);
   if(SL_price<lowestSLAllowed)
     {
      SL_price=lowestSLAllowed;
      ObjectSetDouble(0,slButtonID,OBJPROP_PRICE,lowestSLAllowed);
     }

   visualRRDialog.SetSL(SL_price);
   visualRRDialog.SetTP(symbolInfo.Ask()+(symbolInfo.Ask()-SL_price)*visualRRDialog.GetRRRRatio());

   visualRRDialog.SetMaxTicksLoss(MM.CalcMaxTicksLoss());
   visualRRDialog.SetOrderEquityRisk(MM.CalcOrderEquityRisk(symbolInfo.Ask(), 
                                     SL_price, visualRRDialog.GetOrderLots()));
   visualRRDialog.SetOrderEquityReward(MM.CalcOrderEquityReward(symbolInfo.Ask(), SL_price, 
                                       visualRRDialog.GetOrderLots(), visualRRDialog.GetRRRRatio()));
   visualRRDialog.Refresh();
   rectUpdate(visualRRDialog.GetOrderType());

   ChartRedraw();
  }

EA_onTick() her yeni tik geldiğinde çalıştırılır. Hesaplamalar sadece, emir henüz oluşturulmadıysa ve zararı durdur seviyesi halihazırda SL_arrow işaretçisinin sürüklenmesi yoluyla seçilmişse gerçekleştirilir.

Emir oluşturulduktan sonra risk ve ödül ve TP seviyesi ve ayrıca risk ve ödülün yeniden çizilmesi gerekmez. 

void EA_onTick()
  {
   if(SL_price!=0.0 && orderPlaced==false)
     {
      double lotSize=0.0;
      SL_price=visualRRDialog.GetSL();
      symbolInfo.RefreshRates();

      if(visualRRDialog.GetOrderType()==ORDER_TYPE_BUY)
         lotSize=MM.CheckOpenLong(symbolInfo.Ask(),SL_price);
      else if(visualRRDialog.GetOrderType()==ORDER_TYPE_SELL)
         lotSize=MM.CheckOpenShort(symbolInfo.Ask(),SL_price);

      visualRRDialog.SetMaxAllowedLots(lotSize);
      if(visualRRDialog.GetOrderLots()>lotSize) visualRRDialog.SetOrderLots(lotSize);

      visualRRDialog.SetMaxTicksLoss(MM.CalcMaxTicksLoss());

      if(visualRRDialog.GetOrderType()==ORDER_TYPE_BUY)
        {
         visualRRDialog.SetTP(symbolInfo.Ask()+(symbolInfo.Ask()-SL_price)*visualRRDialog.GetRRRRatio());
         visualRRDialog.SetOrderEquityRisk(MM.CalcOrderEquityRisk(symbolInfo.Ask(), 
                                           SL_price, visualRRDialog.GetOrderLots()));
         visualRRDialog.SetOrderEquityReward(MM.CalcOrderEquityReward(symbolInfo.Ask(), SL_price, 
                                             visualRRDialog.GetOrderLots(), visualRRDialog.GetRRRRatio()));
        }
      else if(visualRRDialog.GetOrderType()==ORDER_TYPE_SELL)
        {
         visualRRDialog.SetTP(symbolInfo.Bid()-(SL_price-symbolInfo.Bid())*visualRRDialog.GetRRRRatio());
         visualRRDialog.SetOrderEquityRisk(MM.CalcOrderEquityRisk(
                                           symbolInfo.Bid(), SL_price, visualRRDialog.GetOrderLots()));
         visualRRDialog.SetOrderEquityReward(MM.CalcOrderEquityReward(symbolInfo.Bid(), SL_price, 
                                             visualRRDialog.GetOrderLots(), visualRRDialog.GetRRRRatio()));
        }
      visualRRDialog.Refresh();
      rectUpdate(visualRRDialog.GetOrderType());
     }

   ChartRedraw(0);
  }

Renkli risk ve ödül dikdörtgenlerini yeniden çizmekten rectUpdate() fonksiyonu sorumludur. Kontrol noktaları SL_arrow nesne başlangıç zamanı, emir türüne bağlı olarak mevcut Satış veya Teklif fiyatı değeri ve SL ve TP seviyeleridir. Açık pembe dikdörtgen mevcut fiyat ve SL seviyesi arasındaki fiyat aralığını gösterir ve açık yeşil dikdörtgen mevcut fiyat ve TP seviyesi arasındaki fiyat aralığını gösterir.

Her iki dikdörtgen SL ve TP fiyat seviyeleri üzerinde risk/ödül oranı etkisini gözlemlemek ve alım satımı girmeden önce riski ayarlamaya yardımcı olmak için harika bir araçtır.

void rectUpdate(ENUM_ORDER_TYPE orderType)
  {
   symbolInfo.RefreshRates();
   currentTime=TimeCurrent();
   SL_arrow.GetInteger(OBJPROP_TIME,0,startTime);

   if(orderType==ORDER_TYPE_BUY)
     {
      rectReward.Create(0,rewardRectID,0,startTime,symbolInfo.Ask(),currentTime,symbolInfo.Ask()+
                       (symbolInfo.Ask()-visualRRDialog.GetSL())*visualRRDialog.GetRRRRatio());
      rectReward.Color(LightGreen);
      rectReward.Background(true);

      rectRisk.Create(0,riskRectID,0,startTime,visualRRDialog.GetSL(),currentTime,symbolInfo.Ask());
      rectRisk.Color(LightPink);
      rectRisk.Background(true);
     }
   else if(orderType==ORDER_TYPE_SELL)
     {
      rectReward.Create(0,rewardRectID,0,startTime,symbolInfo.Bid(),currentTime,symbolInfo.Bid()-
                        (visualRRDialog.GetSL()-symbolInfo.Bid())*visualRRDialog.GetRRRRatio());
      rectReward.Color(LightGreen);
      rectReward.Background(true);

      rectRisk.Create(0,riskRectID,0,startTime,visualRRDialog.GetSL(),currentTime,symbolInfo.Bid());
      rectRisk.Color(LightPink);
      rectRisk.Background(true);
     }
  }

 

7. Demo

Lütfen aşağıda çalışan Uzman Danışmanı (EA) eylem halindeyken gösteren demoyu gözlemleyin. 01/11/2010 Pazartesi tarihinde piyasa açıldıktan kısa süre sonraki büyük yeniden sıçrama sonrasında satış emri yapıyorum.

En iyi görüntüleme deneyimi için lütfen videoyu tam ekran ve kaliteyi 480p olarak ayarlayın. Yorumlar videoya dahil edilmiştir:

 

Sonuç

Aşağıdaki makalede, önceden tanımlı risk ve risk/ödül oranına dayalı manuel alım satım için etkileşimli Uzman Danışman (EA) oluşturmanın bir yolunu sundum.

Grafikte içeriği görüntülemek için standart sınıfların nasıl kullanılacağını ve yeni veri girmek ve sürükle ve bırak nesnelerini işlemek için grafik etkinliklerinin nasıl işleneceğini gösterdim. Sunduğum fikirlerin MQL5’te başka yapılandırılabilir görsel araçlar oluşturmak için temel görevi göreceğini ümit ediyorum.

Tüm kaynak dosyaları ve bitmap’ler ektedir.

MetaQuotes Ltd tarafından İngilizceden çevrilmiştir.
Orijinal makale: https://www.mql5.com/en/articles/192

Ekli dosyalar |
visualrrea.mq5 (13.84 KB)
crrdialog.mqh (13.95 KB)
visualrrids.mqh (0.8 KB)
images.zip (159.05 KB)
CChartObject sınıfına dayalı yeni GUI pencere öğelerinin tasarlanması ve uygulanması CChartObject sınıfına dayalı yeni GUI pencere öğelerinin tasarlanması ve uygulanması
GUI arayüzlü yarı otomatik Uzman Danışman (EA) üzerine önceki makaleyi yazdıktan sonra arayüzün daha karmaşık göstergeler ve Uzman Danışman (EA) için bazı yeni işlevlerle geliştirilmesinin istendiği ortaya çıktı. MQL5 standart kitaplık sınıfları ile tanıştıktan sonra yeni pencere öğelerini uyguladım. Bu makale, göstergelerde ve Uzman Danışmanlarda (EA) kullanılabilecek yeni MQL5 GUI pencere öğelerini tasarlamaya ve uygulamaya yönelik bir işlemi açıklamaktadır. Makalede sunulan pencere öğeleri CChartObjectSpinner, CChartObjectProgressBar ve CChartObjectEditTable’dır.
William Blau'nun MQL5'teki Göstergeleri ve Alım Satım Sistemleri. Bölüm 1: Göstergeler William Blau'nun MQL5'teki Göstergeleri ve Alım Satım Sistemleri. Bölüm 1: Göstergeler
Makalede, William Blau'nun "Momentum, Direction, and Divergence" kitabında açıklanan göstergeler sunulmaktadır. William Blau'nun yaklaşımı, fiyat eğrisindeki dalgalanmaları yaklaşık olarak hızlı ve doğru bir şekilde tahmin etmemize, fiyat hareketleri trendini ve dönüm noktalarını belirlememize ve fiyat gürültüsünü ortadan kaldırmamıza olanak tanır. Aynı zamanda, piyasanın aşırı alım/aşırı satım durumlarını ve bir trendin sona erdiğini ve fiyat hareketinin tersine döndüğünü gösteren sinyalleri de tespit edebiliyoruz.
MetaTrader 5’te Paralel Hesaplamalar MetaTrader 5’te Paralel Hesaplamalar
İnsanlık tarihi boyunca zaman büyük bir değer olmuştur ve bunu gereksiz şekilde israf etmemeye çalışıyoruz. Bu makale, bilgisayarınız çok çekirdekli bir işlemciye sahipse Uzman Danışmanınızın (EA) çalışmasını nasıl hızlandıracağınızı açıklayacaktır. Ayrıca, önerilen yöntemin uygulaması MQL5 dışında başka hiçbir dilin bilinmesini gerektirmez.
Spektrum Analizörü Oluşturma Spektrum Analizörü Oluşturma
Bu makale, okuyucularını MQL5 dilinin grafik nesnelerini kullanmanın olası bir varyantı hakkında bilgilendirmeyi amaçlamaktadır. Ayrıca, grafik nesneleri kullanarak basit bir spektrum analizörü yönetme panelini uygulayan bir gösterge analiz edilmektedir. Makale, MQL5'in temelleri hakkında bilgi sahibi olan okuyuculara yöneliktir.