English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Dr. Tradelove veya Ben Endişelenmeyi Nasıl Bıraktım ve Kendi Kendine Çalışan Bir Expert Advisor'ı Nasıl Yarattım?

Dr. Tradelove veya Ben Endişelenmeyi Nasıl Bıraktım ve Kendi Kendine Çalışan Bir Expert Advisor'ı Nasıl Yarattım?

MetaTrader 5Ticaret | 22 Aralık 2021, 14:05
72 0
Roman Zamozhnyy
Roman Zamozhnyy

Kavram

Expert Advisor'ı oluşturduktan sonra, optimal parametreleri seçmek için yerleşik Strateji Test Cihazı kullanmaya başvuruyoruz. Bunları seçtikten sonra Expert Advisor'ı çalıştırıyoruz ve bunda herhangi bir önemli değişiklik meydana geldiğinde, Expert Advisor durduruluyor ve Strateji Test Cihazı kullanılarak tekrar tekrar optimize ediliyor ve bu böyle devam ediyor.

Yeniden optimizasyon karar verme ve yeniden optimizasyon işlemlerini, doğal olarak işini kesintiye uğratmadan Expert Advisor'a bir süreç olarak atayabilir miyiz?

Bu sorunun çözümlerinden biri için Quantum "Uyarlanabilir Alım Satım Sistemleri ve MetaTrader5 Terminalinde Kullanımları" başlıklı makalesinde, aralarından şimdiye kadar en yüksek karı getiren bir stratejinin seçildiği birkaç (sınırsız sayıda) sanal alım satım stratejisinin yanı sıra gerçek bir alım satım sisteminin kullanılmasını önermiştir. Belirli bir sabit çubuk değeri aşıldıktan sonra alım satım stratejisini değiştirme kararı benimsenir.

Joo tarafından "Genetik Algoritmalar - Çok Kolay!" başlıklı makalesinde ortaya koyduğu genetik algoritma (GA) kodunu kullanmayı öneriyorum. Bu tür bir Expert Advisor'ın uygulamasına bir göz atalım (aşağıdaki örneklerden biri, Otomatik Alım Satım Şampiyonası 2011'e katılım için önerilen bir EA'dır).


Devam eden çalışma

Dolayısıyla Expert Advisor'ın neler yapabilmesi gerektiğini belirlememiz gerekiyor. İlk olarak, seçilen stratejiyi kullanarak alım satım işlemi yapılacağını söylemeye gerek yok. İkincisi, bir karar vermek: Yeniden optimize etme zamanının gelip gelmediği (giriş parametrelerinin yeni bir optimizasyonunu gerçekleştirmek için). Ve üçüncüsü, GA'yı kullanarak yeniden optimize etmek. Öncelikle, en basit yeniden optimizasyonu gözden geçireceğiz - Bir strateji var ve biz yalnızca yeni parametreleri seçiyoruz. Daha sonra, GA'yı kullanarak değişen bir piyasa ortamında başka bir strateji seçip seçemeyeceğimizi ve seçebiliyorsak bunun nasıl yapılabileceğini göreceğiz.

Ayrıca, uygunluk işlevinde simülasyonu kolaylaştırmak için tek bir enstrümanda yalnızca tamamlanmış çubuklarla alım satım işlemi yapma kararı alıyoruz. Ek pozisyonlar ve kısmi kapanışlar olmayacak. Sabit durdurmaları ve takip eden zarar durdurucuları kullanmayı tercih edenler, uygunluk işlevinde Zararı Durdur ve Kar Al talimatı kontrollerini uygulamak için "MetaTrader 5 Strateji Test Cihazı'nda Tick Oluşturma Algoritması" başlıklı makaleye başvurabilirler. Aşağıdaki akıllı ifadeyi genişleteceğim:

Uygunluk işlevinde, Test Cihazında "Yalnızca Açılış Fiyatları" olarak bilinen bir test modunu simüle ediyorum. ANCAK! Bunun uygunluk işlevindeki tek olası test süreci simülasyonu olduğu anlamına gelmez. Daha titiz kişiler, "Her Tick" modunu kullanarak bir uygunluk işlevi testi uygulamak isteyebilir. Tekerleği yeniden icat etmemek veya "her tick"i telafi etmemek için MetaQuotes tarafından geliştirilen mevcut bir algoritmaya dikkatlerini çekmek istiyorum. Başka bir deyişle, bu makaleyi okuduktan sonra, FF'de zararı durdurmalar ve kar almaların doğru simülasyonu için gerekli bir koşul olan uygunluk işlevinde "Her Tick" modunu simüle edebileceksiniz.

Ana noktaya - strateji uygulamasına - geçmeden önce, kısaca teknik özellikleri gözden geçirelim ve yeni bir çubuğun açılmasının yanı sıra pozisyonların açılıp kapatılmasını tanımlayan yardımcı işlevleri uygulayalım:

//+------------------------------------------------------------------+
//| Define whether a new bar has opened                              |
//+------------------------------------------------------------------+
bool isNewBars()
  {
   CopyTime(s,tf,0,1,curBT);
   TimeToStruct(curBT[0],curT);
   if(tf==PERIOD_M1||
      tf==PERIOD_M2||
      tf==PERIOD_M3||
      tf==PERIOD_M4||
      tf==PERIOD_M5||
      tf==PERIOD_M6||
      tf==PERIOD_M10||
      tf==PERIOD_M12||
      tf==PERIOD_M15||
      tf==PERIOD_M20||
      tf==PERIOD_M30)
      if(curT.min!=prevT.min)
        {
         prevBT[0]=curBT[0];
         TimeToStruct(prevBT[0],prevT);
         return(true);
        };
   if(tf==PERIOD_H1||
      tf==PERIOD_H2||
      tf==PERIOD_H3||
      tf==PERIOD_H4||
      tf==PERIOD_H6||
      tf==PERIOD_H8||
      tf==PERIOD_M12)
      if(curT.hour!=prevT.hour)
        {
         prevBT[0]=curBT[0];
         TimeToStruct(prevBT[0],prevT);
         return(true);
        };
   if(tf==PERIOD_D1||
      tf==PERIOD_W1)
      if(curT.day!=prevT.day)
        {
         prevBT[0]=curBT[0];
         TimeToStruct(prevBT[0],prevT);
         return(true);
        };
   if(tf==PERIOD_MN1)
      if(curT.mon!=prevT.mon)
        {
         prevBT[0]=curBT[0];
         TimeToStruct(prevBT[0],prevT);
         return(true);
        };
   return(false);
  }
//+------------------------------------------------------------------+
//|  ClosePosition                                                   |
//+------------------------------------------------------------------+
void ClosePosition()
  {
   request.action=TRADE_ACTION_DEAL;
   request.symbol=PositionGetSymbol(0);
   if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY) request.type=ORDER_TYPE_SELL; 
   else request.type=ORDER_TYPE_BUY;
   request.type_filling=ORDER_FILLING_FOK;
   if(SymbolInfoInteger(PositionGetSymbol(0),SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_REQUEST||
      SymbolInfoInteger(PositionGetSymbol(0),SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_INSTANT)
     {
      request.sl=NULL;
      request.tp=NULL;
      request.deviation=100;
     }
   while(PositionsTotal()>0)
     {
      request.volume=NormalizeDouble(MathMin(PositionGetDouble(POSITION_VOLUME),SymbolInfoDouble(PositionGetSymbol(0),SYMBOL_VOLUME_MAX)),2);
      if(SymbolInfoInteger(PositionGetSymbol(0),SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_REQUEST||
         SymbolInfoInteger(PositionGetSymbol(0),SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_INSTANT)
        {
         if(request.type==ORDER_TYPE_SELL) request.price=SymbolInfoDouble(s,SYMBOL_BID);
         else request.price=SymbolInfoDouble(s,SYMBOL_ASK);
        }
      OrderSend(request,result);
      Sleep(10000);
     }
  }
//+------------------------------------------------------------------+
//|  OpenPosition                                                    |
//+------------------------------------------------------------------+
void OpenPosition()
  {
   double vol;
   request.action=TRADE_ACTION_DEAL;
   request.symbol=s;
   request.type_filling=ORDER_FILLING_FOK;
   if(SymbolInfoInteger(s,SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_REQUEST||
      SymbolInfoInteger(s,SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_INSTANT)
     {
      request.sl=NULL;
      request.tp=NULL;
      request.deviation=100;
     }
   vol=MathFloor(AccountInfoDouble(ACCOUNT_FREEMARGIN)*optF*AccountInfoInteger(ACCOUNT_LEVERAGE)
       /(SymbolInfoDouble(s,SYMBOL_TRADE_CONTRACT_SIZE)*SymbolInfoDouble(s,SYMBOL_VOLUME_STEP)))*SymbolInfoDouble(s,SYMBOL_VOLUME_STEP);
   vol=MathMax(vol,SymbolInfoDouble(s,SYMBOL_VOLUME_MIN));
   vol=MathMin(vol,GetPossibleLots()*0.95);
   if(SymbolInfoDouble(s,SYMBOL_VOLUME_LIMIT)!=0) vol=NormalizeDouble(MathMin(vol,SymbolInfoDouble(s,SYMBOL_VOLUME_LIMIT)),2);
   request.volume=NormalizeDouble(MathMin(vol,SymbolInfoDouble(s,SYMBOL_VOLUME_MAX)),2);
   while(PositionSelect(s)==false)
     {
      if(SymbolInfoInteger(s,SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_REQUEST||
         SymbolInfoInteger(s,SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_INSTANT)
        {
         if(request.type==ORDER_TYPE_SELL) request.price=SymbolInfoDouble(s,SYMBOL_BID); 
         else request.price=SymbolInfoDouble(s,SYMBOL_ASK);
        }
      OrderSend(request,result);
      Sleep(10000);
      PositionSelect(s);
     }
   while(PositionGetDouble(POSITION_VOLUME)<vol)
     {
      request.volume=NormalizeDouble(MathMin(vol-PositionGetDouble(POSITION_VOLUME),SymbolInfoDouble(s,SYMBOL_VOLUME_MAX)),2);
      if(SymbolInfoInteger(PositionGetSymbol(0),SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_REQUEST||
         SymbolInfoInteger(PositionGetSymbol(0),SYMBOL_TRADE_EXEMODE)==SYMBOL_TRADE_EXECUTION_INSTANT)
        {
         if(request.type==ORDER_TYPE_SELL) request.price=SymbolInfoDouble(s,SYMBOL_BID);
         else request.price=SymbolInfoDouble(s,SYMBOL_ASK);
        }
      OrderSend(request,result);
      Sleep(10000);
      PositionSelect(s);
     }
  }
//+------------------------------------------------------------------+

Dikkatli bir şekilde değerlendirdikten sonra, pozisyon açma işlevinde üç önemli parametreyi fark edebilirsiniz: s ve optF değişkenleri ve GetPossibleLots() işlev çağrısı:

  • s - GA tarafından optimize edilen değişkenlerden biri olan alım satım enstrümanı,
  • optF - Alım satım için kullanılacak mevduatın bir kısmı (GA tarafından optimize edilmiş başka bir değişken), 
  • GetPossibleLots() işlevi - Alım satım için kullanılacak mevduat kısmını döndürür:
//+------------------------------------------------------------------+
//|  GetPossibleLots                                                 |
//+------------------------------------------------------------------+
double GetPossibleLots()
  {
   request.volume=1.0;
   if(request.type==ORDER_TYPE_SELL) request.price=SymbolInfoDouble(s,SYMBOL_BID);
   else request.price=SymbolInfoDouble(s,SYMBOL_ASK);
   OrderCheck(request,check);
   return(NormalizeDouble(AccountInfoDouble(ACCOUNT_FREEMARGIN)/check.margin,2));
  }

Anlatımın düzenini biraz bozarak, tüm Expert Advisor'lar için ortak olan ve İkinci aşamada gerekli olan iki işlevi daha tanıtıyoruz:

//+------------------------------------------------------------------+
//|  InitRelDD                                                       |
//+------------------------------------------------------------------+
void InitRelDD()
  {
   ulong DealTicket;
   double curBalance;
   prevBT[0]=D'2000.01.01 00:00:00';
   TimeToStruct(prevBT[0],prevT);
   curBalance=AccountInfoDouble(ACCOUNT_BALANCE);
   maxBalance=curBalance;
   HistorySelect(D'2000.01.01 00:00:00',TimeCurrent());
   for(int i=HistoryDealsTotal();i>0;i--)
     {
      DealTicket=HistoryDealGetTicket(i);
      curBalance=curBalance+HistoryDealGetDouble(DealTicket,DEAL_PROFIT);
      if(curBalance>maxBalance) maxBalance=curBalance;
     }
  }
//+------------------------------------------------------------------+
//|  GetRelDD                                                        |
//+------------------------------------------------------------------+
double GetRelDD()
  {
   if(AccountInfoDouble(ACCOUNT_BALANCE)>maxBalance) maxBalance=AccountInfoDouble(ACCOUNT_BALANCE);
   return((maxBalance-AccountInfoDouble(ACCOUNT_BALANCE))/maxBalance);
  }

Burada ne görebiliriz? İlk işlev maksimum hesap bakiyesi değerini belirler, ikinci işlev hesabın göreli mevcut düşüşünü hesaplar. Özellikleri, İkinci aşamanın açıklamasında ayrıntılı olarak açıklanacaktır.

    Bu şekilde Expert Advisor'lara geçiyoruz. Yeni başlayanlar olduğumuz için, bir strateji seçmek için bir Expert Advisor almayacağız, ancak aşağıdaki stratejilerle iki Expert Advisor'ı kesinlikle uygulayacağız:
    • Biri hareketli ortalamaların kesişim noktalarını kullanarak alım satım işlemi yapar (Altın Kesişim - bir enstrüman alıyoruz, Ölüm Kesişimi - satıyoruz);
    • Diğeri ise son beş alım satım işlemi seansında [0..1] aralığında fiyat değişiklikleri alan basit bir nöral ağdır.

    Algoritmik olarak kendi kendini optimize eden bir Expert Advisor'ın çalışması aşağıdaki gibi örneklendirilebilir:

    1. Expert Advisor tarafından kullanılan değişkenlerin başlatılması: Gösterge arabelleklerini tanımlayın ve başlatın veya nöral ağ topolojisini ayarlayın (bir katmandaki katman/nöron sayısı; tüm katmanlarda nöron sayısının aynı olduğu basit bir nöral ağ örnek olarak verilebilir), çalışma zaman dilimini ayarlayın. Ayrıca, muhtemelen en önemli adıma - sırayla en önde gelen işlevi - uygunluk işlevini (bundan sonra - FF olarak anılacaktır) ele alan Genetik Optimizasyon işlevi diyoruz.

      ÖNEMLİ! Her alım satım stratejisi için yeni bir FF vardır; yani her seferinde yeniden oluşturulur, örneğin tek bir hareketli ortalama için FF, iki hareketli ortalama için FF'den tamamen farklıdır ve nöral ağ FF'den önemli ölçüde farklılık gösterir.

      Expert Advisor'larımdaki FF performans sonucu, göreceli düşüşün harici bir değişken olarak belirlenen kritik değeri aşmaması koşuluyla maksimum bir bakiyedir (örneklerimizde - 0,5). Başka bir deyişle, bir sonraki GA çalıştırması 100.000 bakiye veriyorsa, göreceli bakiye düşüşü -0,6 iken, FF=0,0 olur. Sizin durumunuzda sevgili Okuyucu, FF sonucu tamamen farklı kriterler getirebilir.

      Genetik Algoritma performans sonuçlarını toplayın: Hareketli ortalamaların kesişimi için bunlar açıkça hareketli ortalama dönemleri olacaktır, bir nöral ağ durumunda sinaps ağırlıkları olacaktır ve her ikisi için (ve diğer Expert Advisor'larım için) ortak sonuç bir sonraki yeniden optimizasyona kadar işlem görecek bir enstrüman ve halihazırda aşina olduğumuz optF'ye, yani alım satım işlemi için kullanılacak mevduatın bir kısmı olacaktır. Kendi takdirinize bağlı olarak FF'nize optimize edilmiş parametreler eklemekte özgürsünüz; örneğin zaman dilimini veya diğer parametreleri de seçebilirsiniz...

      Başlatmadaki son adım, maksimum hesap bakiyesi değerini bulmaktır. Peki bu neden önemli? Çünkü bu, yeniden optimizasyon kararı almak için bir başlangıç noktasıdır.

      ÖNEMLİ! Yeniden optimizasyon kararı nasıl alınır? Göreceli BAKİYE düşüşü, harici bir değişken olarak belirlenen belirli bir kritik değere ulaştığında (örneklerimizde - 0,2), yeniden optimize etmemiz gerekir. Bir Expert Advisor'ın kritik düşüşe ulaşıldığında her çubukta yeniden optimizasyon uygulaması yapmaması için maksimum bakiye değeri mevcut bir değerle değiştirilir.

      Sevgili Okuyucum, yeniden optimizasyonun uygulanması için tamamen farklı bir kritere sahip olabilirsiniz.

    2. Alım satım işlemi devam ediyor.

    3. Her kapatılan pozisyon üzerine, bakiye düşüşünün kritik değere ulaşıp ulaşmadığını kontrol ederiz. Kritik değere ulaşılırsa, GA'yı çalıştırır ve performans sonuçlarını toplarız (bu, yeniden optimizasyondur!)

    4. Ya forex direktöründen dünyanın iflas etmemesi için bir çağrı bekliyoruz ya da (daha sık olarak) Stop Out, Marjin Çağrısı, acil ambulans...

    Aşağıda, hareketli ortalamalar stratejisini (kaynak kodu da mevcuttur) ve nöral ağı kullanan Expert Advisor için yukarıdakilerin programlanmış bir uygulamasını bulabilirsiniz - tümü kaynak kodu olarak.

    Kod, GPL lisansı hüküm ve koşulları kapsamında sağlanır.

    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
       tf=Period();
    //---for bar-to-bar test...
       prevBT[0]=D'2001.01.01';
    //---... long ago
       TimeToStruct(prevBT[0],prevT);
    //--- historical depth (should be set since the optimisation is based on historical data)
       depth=10000;
    //--- copies at a time (should be set since the optimisation is based on historical data)
       count=2;
       ArrayResize(LongBuffer,count);
       ArrayResize(ShortBuffer,count);
       ArrayInitialize(LongBuffer,0);
       ArrayInitialize(ShortBuffer,0);
    //--- calling the neural network genetic optimisation function
       GA();
    //--- getting the optimised neural network parameters and other variables
       GetTrainResults();
    //--- getting the account drawdown
       InitRelDD();
       return(0);
      }
    //+------------------------------------------------------------------+
    //| Expert tick function                                             |
    //+------------------------------------------------------------------+
    void OnTick()
      {
       if(isNewBars()==true)
         {
          bool trig=false;
          CopyBuffer(MAshort,0,0,count,ShortBuffer);
          CopyBuffer(MAlong,0,0,count,LongBuffer);
          if(LongBuffer[0]>LongBuffer[1] && ShortBuffer[0]>LongBuffer[0] && ShortBuffer[1]<LongBuffer[1])
            {
             if(PositionsTotal()>0)
               {
                if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
                  {
                   ClosePosition();
                   trig=true;
                  }
               }
            }
          if(LongBuffer[0]<LongBuffer[1] && ShortBuffer[0]<LongBuffer[0] && ShortBuffer[1]>LongBuffer[1])
            {
             if(PositionsTotal()>0)
               {
                if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
                  {
                   ClosePosition();
                   trig=true;
                  }
               }
            }
          if(trig==true)
            {
             //--- if the account drawdown has exceeded the allowable value:
             if(GetRelDD()>maxDD)
               {
                //--- calling the neural network genetic optimisation function
                GA();
                //--- getting the optimised neural network parameters and other variables
                GetTrainResults();
                //--- readings of the drawdown will from now on be based on the current balance instead of the maximum balance
                maxBalance=AccountInfoDouble(ACCOUNT_BALANCE);
               }
            }
          CopyBuffer(MAshort,0,0,count,ShortBuffer);
          CopyBuffer(MAlong,0,0,count,LongBuffer);
          if(LongBuffer[0]>LongBuffer[1] && ShortBuffer[0]>LongBuffer[0] && ShortBuffer[1]<LongBuffer[1])
            {
             request.type=ORDER_TYPE_SELL;
             OpenPosition();
            }
          if(LongBuffer[0]<LongBuffer[1] && ShortBuffer[0]<LongBuffer[0] && ShortBuffer[1]>LongBuffer[1])
            {
             request.type=ORDER_TYPE_BUY;
             OpenPosition();
            }
         };
      }
    //+------------------------------------------------------------------+
    //| Preparing and calling the genetic optimizer                      |
    //+------------------------------------------------------------------+
    void GA()
      {
    //--- number of genes (equal to the number of optimised variables), 
    //--- all of them should be specified in the FitnessFunction())
       GeneCount      =OptParamCount+2;    
    //--- number of chromosomes in a colony
       ChromosomeCount=GeneCount*11;
    //--- minimum search range
       RangeMinimum   =0.0;
    //--- maximum search range
       RangeMaximum   =1.0;
    //--- search pitch
       Precision      =0.0001;
    //--- 1 is a minimum, anything else is a maximum
       OptimizeMethod =2;                                                 
       ArrayResize(Chromosome,GeneCount+1);
       ArrayInitialize(Chromosome,0);
    //--- number of epochs without any improvement
       Epoch          =100;                                               
    //--- ratio of replication, natural mutation, artificial mutation, gene borrowing, 
    //--- crossingover, interval boundary displacement ratio, every gene mutation probabilty, %
       UGA(100.0,1.0,1.0,1.0,1.0,0.5,1.0);                                
      }
    //+------------------------------------------------------------------+
    //| Fitness function for neural network genetic optimizer:           | 
    //| selecting a pair, optF, synapse weights;                         |
    //| anything can be optimised but it is necessary                    |
    //| to carefully monitor the number of genes                         |
    //+------------------------------------------------------------------+
    void FitnessFunction(int chromos)
      {
       int    b;
    //--- is there an open position?
       bool   trig=false;
    //--- direction of an open position
       string dir="";
    //--- opening price
       double OpenPrice=0;
    //--- intermediary between a gene colony and optimised parameters
       int    z;
    //--- current balance
       double t=cap;
    //--- maximum balance
       double maxt=t;
    //--- absolute drawdown
       double aDD=0;
    //--- relative drawdown
       double rDD=0.000001;
    //--- fitness function proper
       double ff=0;
    //--- GA is selecting a pair
       z=(int)MathRound(Colony[GeneCount-1][chromos]*12);
       switch(z)
         {
          case  0: {s="AUDUSD"; break;};
          case  1: {s="AUDUSD"; break;};
          case  2: {s="EURAUD"; break;};
          case  3: {s="EURCHF"; break;};
          case  4: {s="EURGBP"; break;};
          case  5: {s="EURJPY"; break;};
          case  6: {s="EURUSD"; break;};
          case  7: {s="GBPCHF"; break;};
          case  8: {s="GBPJPY"; break;};
          case  9: {s="GBPUSD"; break;};
          case 10: {s="USDCAD"; break;};
          case 11: {s="USDCHF"; break;};
          case 12: {s="USDJPY"; break;};
          default: {s="EURUSD"; break;};
         }
       MAshort=iMA(s,tf,(int)MathRound(Colony[1][chromos]*MaxMAPeriod)+1,0,MODE_SMA,PRICE_OPEN);
       MAlong =iMA(s,tf,(int)MathRound(Colony[2][chromos]*MaxMAPeriod)+1,0,MODE_SMA,PRICE_OPEN);
       dig=MathPow(10.0,(double)SymbolInfoInteger(s,SYMBOL_DIGITS));
       
    //--- GA is selecting the optimal F
       optF=Colony[GeneCount][chromos];                                   
       
       leverage=AccountInfoInteger(ACCOUNT_LEVERAGE);
       contractSize=SymbolInfoDouble(s,SYMBOL_TRADE_CONTRACT_SIZE);
       b=MathMin(Bars(s,tf)-1-count-MaxMAPeriod,depth);
       
    //--- for a neural network using historical data - where the data is copied from
       for(from=b;from>=1;from--) 
         {
          CopyBuffer(MAshort,0,from,count,ShortBuffer);
          CopyBuffer(MAlong,0,from,count,LongBuffer);
          if(LongBuffer[0]>LongBuffer[1] && ShortBuffer[0]>LongBuffer[0] && ShortBuffer[1]<LongBuffer[1])
            {
             if(trig==false)
               {
                CopyOpen(s,tf,from,count,o);
                OpenPrice=o[1];
                dir="SELL";
                trig=true;
               }
             else
               {
                if(dir=="BUY")
                  {
                   CopyOpen(s,tf,from,count,o);
                   if(t>0) t=t+t*optF*leverage*(o[1]-OpenPrice)*dig/contractSize; else t=0;
                   if(t>maxt) {maxt=t; aDD=0;} else if((maxt-t)>aDD) aDD=maxt-t;
                   if((maxt>0) && (aDD/maxt>rDD)) rDD=aDD/maxt;
                   OpenPrice=o[1];
                   dir="SELL";
                   trig=true;
                  }
               }
            }
          if(LongBuffer[0]<LongBuffer[1] && ShortBuffer[0]<LongBuffer[0] && ShortBuffer[1]>LongBuffer[1])
            {
             if(trig==false)
               {
                CopyOpen(s,tf,from,count,o);
                OpenPrice=o[1];
                dir="BUY";
                trig=true;
               }
             else
               {
                if(dir=="SELL")
                  {
                   CopyOpen(s,tf,from,count,o);
                   if(t>0) t=t+t*optF*leverage*(OpenPrice-o[1])*dig/contractSize; else t=0;
                   if(t>maxt) {maxt=t; aDD=0;} else if((maxt-t)>aDD) aDD=maxt-t;
                   if((maxt>0) && (aDD/maxt>rDD)) rDD=aDD/maxt;
                   OpenPrice=o[1];
                   dir="BUY";
                   trig=true;
                  }
               }
            }
         }
       if(rDD<=trainDD) ff=t; else ff=0.0;
       AmountStartsFF++;
       Colony[0][chromos]=ff;
      }
    
    //+---------------------------------------------------------------------+
    //| getting the optimized neural network parameters and other variables |
    //| should always be equal to the number of genes                       |
    //+---------------------------------------------------------------------+
    void GetTrainResults()
      {
    //---  intermediary between a gene colony and optimised parameters
       int z;                                                             
       MAshort=iMA(s,tf,(int)MathRound(Chromosome[1]*MaxMAPeriod)+1,0,MODE_SMA,PRICE_OPEN);
       MAlong =iMA(s,tf,(int)MathRound(Chromosome[2]*MaxMAPeriod)+1,0,MODE_SMA,PRICE_OPEN);
       CopyBuffer(MAshort,0,from,count,ShortBuffer);
       CopyBuffer(MAlong,0,from,count,LongBuffer);
    //--- save the best pair
       z=(int)MathRound(Chromosome[GeneCount-1]*12);                      
       switch(z)
         {
          case  0: {s="AUDUSD"; break;};
          case  1: {s="AUDUSD"; break;};
          case  2: {s="EURAUD"; break;};
          case  3: {s="EURCHF"; break;};
          case  4: {s="EURGBP"; break;};
          case  5: {s="EURJPY"; break;};
          case  6: {s="EURUSD"; break;};
          case  7: {s="GBPCHF"; break;};
          case  8: {s="GBPJPY"; break;};
          case  9: {s="GBPUSD"; break;};
          case 10: {s="USDCAD"; break;};
          case 11: {s="USDCHF"; break;};
          case 12: {s="USDJPY"; break;};
          default: {s="EURUSD"; break;};
         }
    //--- saving the best optimal F
       optF=Chromosome[GeneCount];                                        
      }
    //+------------------------------------------------------------------+

    Algoritmanın ana işlevine, (uygunluk işlevine) bakalım.

    Kendi kendini optimize eden bir Expert Advisor'ın ardındaki tüm fikir, Genetik Algoritmadan (GA işlevi()) optimize edilmiş değişkenlerin girdisini alan uygunluk işlevinde belirli bir süre içinde (örneğin, 10000 barlık bir geçmiş) alım satım sürecinin simülasyonuna ( Test Cihazında olduğu gibi) dayanır. Hareketli ortalamaların kesişimine dayalı bir algoritma olması durumunda, optimize edilmiş değişkenler şunları içerir:

    • Enstrüman (forex'te - bir para birimi çifti); evet, tipik bir çok para birimli Expert Advisor'dır ve Genetik Algoritma bir enstrüman seçer (kod Şampiyonaya katılım için önerilen Expert Advisor'dan alındığı için, sahip olduğu çiftler Şampiyona para birimi çiftlerine karşılık gelir; genel olarak bir broker tarafından fiyat teklifi verilen herhangi bir enstrüman olabilir).
      Not: Ne yazık ki, Expert Advisor test modunda MarketWatch penceresinden çift listesini alamıyor (burada MetaQuotes kullanıcıları sayesinde bunu açıklığa kavuşturduk - Yok artık!). Bu nedenle Test Cihazında Expert Advisor'ı forex ve hisseler için ayrı ayrı çalıştırmak istiyorsanız, FF ve GetTrainResults() işlevinde kendi enstrümanlarınızı belirtmeniz yeterlidir.
    • alım satım için kullanılacak mevduatın bir kısmı;
    • iki hareketli ortalamanın dönemleri.

    Aşağıdaki örneklerde, TEST İÇİN Expert Advisor'ın bir çeşidi gösterilmiştir!

    GERÇEK ALIM SATIM İŞLEMİ kodu, Piyasa İzleme penceresindeki enstrüman listesi kullanılarak önemli ölçüde basitleştirilebilir.

    Bunu FF ve GetTrainResults() işlevinde yapmak için "//--- GA bir çift seçiyor" ve "//--- en iyi çifti kaydediyor" yorumlarıyla yazmanız yeterlidir:

    //--- GA is selecting a pair
      z=(int)MathRound(Colony[GeneCount-1][chromos]*(SymbolsTotal(true)-1));
      s=SymbolName(z,true);

    Bu nedenle, FF'nin başında, gerektiğinde, geçmişe dayalı alım satımın simülasyonu için değişkenleri belirler ve başlatırız. Bir sonraki aşamada Genetik Algoritmadan optimize edilmiş değişkenlerin farklı değerlerini toplarız; örneğin bu satırdan "optF=Colony[GeneCount][chromos]; mevduat kısmı değeri GA'dan FF'ye aktarılır.

    Ayrıca geçmişteki mevcut çubuk sayısını da kontrol ederiz ve 10000'inci çubuktan veya ilk kullanılabilir çubuktan başlayarak "Yalnızca açılış fiyatları" modunda fiyat teklifi alma ve alım satım kararları verme sürecini simüle ederiz:

    • Hareketli ortalamaların değerlerini arabelleklere kopyalayın;
    • Bunun bir Ölüm Kesişimi olup olmadığını kontrol edin.
    • Ölüm kesişimi varsa ve açık pozisyon yoksa (if(trig==false)) - sanal bir SAT pozisyonu açın (açılış fiyatını ve yönünü unutmayın);
    • Bir Ölüm Kesişimi ve açık bir AL pozisyonu varsa (if(dir=="BUY")) - çubuk açılış fiyatını alın ve aşağıdaki çok önemli üç satıra dikkat edin:
    1. Bir pozisyonun kapanmasını ve bakiyedeki değişikliği simüle eder: cari bakiye, mevduatın işlem görecek kısmı ile çarpılan, açılış ve kapanış fiyatları arasındaki farkla çarpılan ve pip fiyatı (kaba) ile çarpılan bir cari bakiye değeri kadar artırılır;
    2. Mevcut bakiyenin alım satım simülasyonu geçmişi boyunca maksimuma ulaşıp ulaşmadığını kontrol edin; ulaşmadıysa, paradaki maksimum bakiye düşüşünü hesaplayın;
    3. Daha önce hesaplanan para düşüşünü göreceli bakiye düşüşüne dönüştürün;
    • Sanal bir SAT pozisyonu açın (açılış fiyatını ve yönünü unutmayın);
    • benzer kontrolleri ve hesaplamaları Altın Kesişim için de yapın.

    Sanal alım satım işleminin mevcut tüm geçmişini ve simülasyonunu gözden geçirdikten sonra, nihai FF değerini hesaplayın: Hesaplanan göreceli bakiye düşüşü, test için ayarlanandan azsa, FF=bakiye, aksi takdirde FF=0'dır. Genetik Algoritma, uygunluk işlevinin maksimize edilmesini amaçlar!

    Sonuç olarak, Genetik Algoritma, enstrümanların çeşitli değerlerini, mevduat kısımlarını ve hareketli ortalamaların dönemlerini vererek, minimum (minimum, kullanıcı tarafından belirlenir) göreceli düşüşte bakiyeyi maksimize eden değerleri bulacaktır.


    Sonuç

    Kısa sonuç şu şekildedir: Kendi kendini eğiten bir Expert Advisor oluşturmak kolaydır, zor kısım ne girileceğini bulmaktır (önemli olan fikirdir, uygulama yalnızca teknik bir konudur).

    Kötümserlerin "İşe yarıyor mu?" sorusuna bir cevabım var - Evet, işe yarıyor; iyimserlere sözümse - Bu bir Kutsal Kase değil.

    Önerilen yöntem ile Quantum'un yöntemi arasındaki temel fark nedir? Bu, MA'ları kullanan Expert Advisor'ları karşılaştırarak en iyi şekilde örneklendirilebilir:

    1. Uyarlanabilir Alım Satım Sistemi'nde MA'ların dönemlerine ilişkin karar, derlemeden önce ve sıkı bir şekilde kodlanmalıdır ve seçim ancak bu sınırlı sayıdaki varyantlar arasından yapılabilir; Genetik Olarak Optimize Edilmiş Expert Advisor'da derleme öncesi dönemler hakkında herhangi bir karar almıyoruz; bu karar GA tarafından alınacak, varyant sayısı ise yalnızca sağduyu ile sınırlıdır.
    2. Uyarlanabilir Alım Satım Sistemi'nde sanal alım satım çubuktan çubuğadır; bu, Genetik Olarak Optimize Edilmiş Expert Advisor'da nadiren böyledir - ve daha sonra yalnızca yeniden optimizasyon için koşulların ortaya çıkması üzerine. Artan sayıda strateji, parametre ve enstrüman üzerindeki bilgisayar performansı, Uyarlanabilir Alım Satım Sistemi için sınırlayıcı bir faktör olabilir.


    Ek

    Nöral ağın, 01.01.2010 tarihinden itibaren herhangi bir optimizasyon olmadan ve günlük grafiklere dayalı olarak Test Cihazında çalıştırılması durumunda elde ettiğimiz sonuçlar şu şekildedir:

    Strateji Test Cihazı Raporu
    MetaQuotes-Demo (Derleme 523)
    Expert Advisor: ANNExample
    Sembol: EURUSD
    Dönem: Günlük (01.01.2010 - 30.09.2011)
    Giriş parametreleri: trainDD=0,9
    maxDD=0,1
    Aracı: Alpari NZ Limited
    Para birimi: USD
    İlk para yatırma: 10 000.00
    Kaldıraç: 1:100
    Sonuçlar
    Geçmiş kalitesi: %100
    Çubuklar: 454 Tickler: 2554879
    Toplam net kar: -9 094.49 Brüt kar: 29 401.09 Brüt zarar: -38 495.58
    Kar faktörü: 0,76 Beklenen kazanç: -20,53 Marj düzeyi: %732,30
    Kurtarma faktörü: -0,76 Sharpe oranı: -0,06 OnTester sonucu: 0
    Bakiye düşüşü:
    Mutlak bakiye düşüşü: 9 102,56 Maksimum bakiye düşüşü: 11 464.70 (%92,74) Göreceli bakiye düşüşü: %92,74 (11 464.70)
    Hisse senedi düşüşü:
    Mutlak hisse senedi düşüşü: 9 176.99 Maksimum hisse senedi düşüşü: 11 904.00 (%93,53) Göreceli hisse senedi düşüşü: %93,53 (11 904.00)
    Toplam alım satım işlemi: 443 Kısa alım satımlar (kazanan, %): 7 (%14,29) Uzun alım satımlar (kazanan, %): 436 (%53,44)
    Toplam yatırım: 886 Kar alım satımları, (toplam %) 234 (%52,82) Zarar alım satımları (toplam %): 209 (%47,18)
    En büyük kar alım satımı: 1 095.57 En büyük zarar alım satımı: -1 438.85
    Ortalama kar alım satımı: 125.65 Ortalama zarar alım satımı: -184.19
    Maks. ardışık kazanç (para cinsinden kar): 8 (397,45) Maks. ardışık zarar (para cinsinden zarar): 8 (-1 431.44)
    Maks. ardışık kar (kazanç sayısı): 1 095.57 (1) Maks. ardışık zarar (zarar sayısı): -3 433.21 (6)
    Ortalama ardışık kazanç: 2 Maksimum ardışık zararlar: 2

    ve aşağıda, aralarından seçim yapabileceğiniz üç yeniden optimizasyon çeşidi bulunmaktadır:

    ilk...

    Zaman Yatırım Sembol Tür Yön Hacim Fiyat Talimat Swap Kar Bakiye
    2010.01.01 00:00 1   bakiye         0.00 10 000.00 10 000.00
    2010.01.04 00:00 2 AUDUSD alış giriş 0.90 0.89977 2 0.00 0.00 10 000.00
    2010.01.05 00:00 3 AUDUSD satış çıkış 0.90 0.91188 3 5.67 1 089.90 11 095.57
    2010.01.05 00:00 4 AUDUSD alış giriş 0.99 0.91220 4 0.00 0.00 11 095.57
    2010.01.06 00:00 5 AUDUSD satış çıkış 0.99 0.91157 5 6.24 -62.37 11 039.44
    2010.01.06 00:00 6 AUDUSD alış giriş 0.99 0.91190 6 0.00 0.00 11 039.44
    2010.01.07 00:00 7 AUDUSD satış çıkış 0.99 0.91924 7 18.71 726.66 11 784.81


    ikinci...

    Zaman Yatırım Sembol Tür Yön Hacim Fiyat Talimat Komisyon Swap Kar Bakiye
    2010.05.19 00:00 189 AUDUSD satış çıkış 0.36 0.86110 189 0.00 2.27 -595.44 4 221.30
    2010.05.19 00:00 190 EURAUD satış giriş 0.30 1.41280 190 0.00 0.00 0.00 4 221.30
    2010.05.20 00:00 191 EURAUD alış çıkış 0.30 1.46207 191 0.00 7.43 -1 273.26 2 955.47
    2010.05.20 00:00 192 AUDUSD alış giriş 0.21 0.84983 192 0.00 0.00 0.00 2 955.47


    üçüncü

    Zaman Yatırım Sembol Tür Yön Hacim Fiyat Talimat Swap Kar Bakiye
    2010.06.16 00:00 230 GBPCHF alış giriş 0.06 1.67872 230 0.00 0.00 2 128.80
    2010.06.17 00:00 231 GBPCHF satış çıkış 0.06 1.66547 231 0.13 -70.25 2 058.68
    2010.06.17 00:00 232 GBPCHF alış giriş 0.06 1.66635 232 0.00 0.00 2 058.68
    2010.06.18 00:00 233 GBPCHF satış çıkış 0.06 1.64705 233 0.04 -104.14 1 954.58
    2010.06.18 00:00 234 AUDUSD alış giriş 0.09 0.86741 234 0.00 0.00 1 954.58
    2010.06.21 00:00 235 AUDUSD satış çıkış 0.09 0.87184 235 0.57 39.87 1 995.02
    2010.06.21 00:00 236 AUDUSD alış giriş 0.09 0.88105 236 0.00 0.00 1 995.02
    2010.06.22 00:00 237 AUDUSD satış çıkış 0.09 0.87606 237 0.57 -44.91 1 950.68
    2010.06.22 00:00 238 AUDUSD alış giriş 0.09 0.87637 238 0.00 0.00 1 950.68
    2010.06.23 00:00 239 AUDUSD satış çıkış 0.09 0.87140 239 0.57 -44.73 1 906.52
    2010.06.23 00:00 240 AUDUSD alış giriş 0.08 0.87197 240 0.00 0.00 1 906.52
    2010.06.24 00:00 241 AUDUSD satış çıkış 0.08 0.87385 241 1.51 15.04 1 923.07
    2010.06.24 00:00 242 AUDUSD alış giriş 0.08 0.87413 242 0.00 0.00 1 923.07
    2010.06.25 00:00 243 AUDUSD satış çıkış 0.08 0.86632 243 0.50 -62.48 1 861.09
    2010.06.25 00:00 244 AUDUSD alış giriş 0.08 0.86663 244 0.00 0.00 1 861.09
    2010.06.28 00:00 245 AUDUSD satış çıkış 0.08 0.87375 245 0.50 56.96 1 918.55
    2010.06.28 00:00 246 AUDUSD alış giriş 0.08 0.87415 246 0.00 0.00 1 918.55
    2010.06.29 00:00 247 AUDUSD satış çıkış 0.08 0.87140 247 0.50 -22.00 1 897.05
    2010.06.29 00:00 248 AUDUSD alış giriş 0.08 0.87173 248 0.00 0.00 1 897.05
    2010.07.01 00:00 249 AUDUSD satış çıkış 0.08 0.84053 249 2.01 -249.60 1 649.46
    2010.07.01 00:00 250 EURGBP satış giriş 0.07 0.81841 250 0.00 0.00 1 649.46
    2010.07.02 00:00 251 EURGBP alış çıkış 0.07 0.82535 251 -0.04 -73.69 1 575.73
    2010.07.02 00:00 252 EURGBP satış giriş 0.07 0.82498 252 0.00 0.00 1 575.73
    2010.07.05 00:00 253 EURGBP alış çıkış 0.07 0.82676 253 -0.04 -18.93 1 556.76
    2010.07.05 00:00 254 EURGBP satış giriş 0.06 0.82604 254 0.00 0.00 1 556.76
    2010.07.06 00:00 255 EURGBP alış çıkış 0.06 0.82862 255 -0.04 -23.43 1 533.29


    Not Ön çalışma olarak: Yalnızca belirli bir sistemin parametrelerini seçmek değil, aynı zamanda belirli bir anda piyasaya en uygun sistemi seçmek (ipucu - sistem bankasından).


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

    Ekli dosyalar |
    anntrainlib.mqh (9.76 KB)
    matrainlib.mqh (8.94 KB)
    ugalib.mqh (33.26 KB)
    annexample.mq5 (4.32 KB)
    maexample.mq5 (4.22 KB)
    musthavelib.mqh (8.14 KB)
    Ya Hep Ya Hiç Forex Stratejisi Ya Hep Ya Hiç Forex Stratejisi
    Bu makalenin amacı, "Ya Hep Ya Hiç" oyun prensibini uygulayan en basit alım satım stratejisini oluşturmaktır. Karlı bir Expert Advisor oluşturmak istemiyoruz; amacımız, mümkün olan en yüksek olasılıkla ilk mevduatı birkaç kez artırmaktır. ForEx'te köşeyi dönmek veya teknik analiz hakkında hiçbir şey bilmeden ve herhangi bir gösterge kullanmadan her şeyi kaybetmek mümkün mü?
    MetaTrader 5 Platformuna Yeni UI Dilleri Nasıl Eklenir? MetaTrader 5 Platformuna Yeni UI Dilleri Nasıl Eklenir?
    MetaTrader 5 platformunun kullanıcı arayüzü birkaç dile çevrilmiştir. Ana diliniz desteklenen diller arasında değilse endişelenmeyin. MetaQuotes Software Corp. tarafından herkese ücretsiz olarak sunulan özel MetaTrader 5 Çoklu Dil Paketi yardımcı programını kullanarak çeviriyi kolayca uygulayabilirsiniz. Bu makalede, MetaTrader 5 platformuna yeni bir kullanıcı arayüzü dillerinin nasıl ekleneceğine ilişkin bazı örnekler göstereceğiz.
    EA Ağacını kullanarak dakikalar içinde MQL5 Expert Advisor'lar oluşturma: Bölüm Bir EA Ağacını kullanarak dakikalar içinde MQL5 Expert Advisor'lar oluşturma: Bölüm Bir
    EA Ağacı, ilk sürükle ve bırak MetaTrader MQL5 Expert Advisor oluşturucusudur. Kullanımı çok kolay bir grafik kullanıcı arayüzünü kullanarak karmaşık MQL5 oluşturabilirsiniz. EA Ağacı'nda, Expert Advisor'lar kutular birbirine bağlanarak oluşturulur. Kutular MQL5 işlevleri, teknik göstergeler, özel göstergeler veya değerler içerebilir. EA Ağacı, "kutu ağacını" kullanarak Expert Advisor'ın MQL5 kodunu oluşturur.
    UML Araçlarını Kullanarak Expert Advisor Nasıl Geliştirilir? UML Araçlarını Kullanarak Expert Advisor Nasıl Geliştirilir?
    Bu makalede, nesne yönelimli yazılım sistemlerinin görsel modellemesi için kullanılan UML grafik dili kullanılarak Expert Advisor'ların oluşturulması ele alınmaktadır. Bu yaklaşımın temel avantajı, modelleme sürecinin görselleştirilmesidir. Makale, Software Ideas Modeler kullanarak bir Expert Advisor'ın yapısının ve özelliklerinin modellenmesini gösteren bir örnek içermektedir.