English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Expert Advisor'ın Çalışması Sırasında Denge Eğrisinin Eğimini Kontrol Etme

Expert Advisor'ın Çalışması Sırasında Denge Eğrisinin Eğimini Kontrol Etme

MetaTrader 5Ticaret | 15 Aralık 2021, 10:44
77 0
Dmitriy Skub
Dmitriy Skub


Giriş

Bu makalede, bir geri bildirim oluşturmak yoluyla Expert Advisor'ların performansını artırmaya olanak tanıyan yaklaşımlardan biri açıklanmaktadır. Bu durumda, geri bildirim, denge eğrisinin eğiminin ölçülmesine dayalı olacaktır. İş hacmi düzenlenerek eğim kontrolü otomatik olarak yapılır. Bir Expert Advisor aşağıdaki modlarda alım satım işlemi yapabilir: Kesim hacmi ile, lotların iş miktarı ile (başlangıçta ayarlanmış olana göre) ve ara hacim ile. Çalışma modu otomatik olarak değiştirilir.

Geri bildirim zincirinde farklı düzenleyici özellikler kullanılır: Kademeli, histerezisli kademeli, doğrusal. Bu, denge eğrisinin eğimini kontrol eden sistemin belirli bir sistemin özelliklerine göre ayarlanmasını sağlar.

Ana fikir, kendi alım satım sistemini izlerken bir yatırımcı için karar verme sürecini otomatikleştirmektir. Çalışmasının elverişsiz dönemlerinde riskleri azaltmak mantıklıdır. Normal çalışma moduna dönerken riskler başlangıç düzeyine geri yüklenebilir.

Tabi ki, bu sistem her derde deva değildir ve kaybeden bir Expert Advisor'ı karlı bir sisteme dönüştürmeyecektir. Bir şekilde, bu, Expert Advisor'ın bir hesapta önemli kayıplar yaşamasını engelleyen MM'ye (para yönetimi) bir ektir.

Makale, bu işlevin herhangi bir Expert Advisor'ın koduna gömülmesine izin veren bir kitaplık içermektedir.


Çalışma Prensibi

Denge eğrisinin eğimini kontrol eden sistemin çalışma prensibine bir göz atalım. Bir alım satım Expert Advisor'ımız olduğunu varsayalım. Varsayımsal denge eğrisi şu şekilde görünür:

Denge eğrisinin eğimini kontrol eden sistemin çalışma prensibi

Şekil 1. Denge eğrisinin eğimini kontrol eden sistemin çalışma prensibi

Sabit hacimli alım satım işlemleri kullanan Expert Advisor için başlangıç dengesi eğrisi yukarıda gösterilmiştir. Kapanan alım satım işlemleri kırmızı noktalarla gösterilmektedir. Bu noktaları, alım satım işlemi sırasında Expert Advisor'ın denge değişimini temsil eden bir eğri çizgisiyle birleştirelim (kalın siyah çizgi).

Şimdi bu çizginin zaman eksenine olan eğim açısını (ince mavi çizgilerle gösterilen) sürekli olarak takip edeceğiz. Veya daha açık olmak gerekirse, her alım satım işlemini bir sinyalle açmadan önce, eğim açısını önceden kapatılmış iki alım satım işlemiyle (veya açıklamanın daha basit olması için iki alım satım işlemiyle) hesaplayacağız. Eğim açısı belirtilen değerin altına düşerse kontrol sistemimiz çalışmaya başlar, açının hesaplanan değerine ve belirtilen düzenleme işlevine göre hacmi azaltır.

Bu şekilde, alım satım işlemi başarısız bir döneme girerse hacim Т3... Т5 alım satım dönemi içinde Vmax. durumundan Vmin. durumuna düşer. Т5 noktasından sonra alım satım işlemi, belirtilen minimum hacimle alım satım işlemi hacminin reddedilme modunda gerçekleştirilir. Expert Advisor'ın karlılığı geri kazanıldığında ve denge eğrisinin eğim açısı belirlenen değerin üzerine çıktığında hacim artmaya başlar. Bu, Т8...Т10 aralığında gerçekleşir. Т10 noktasından sonra, alım satım işlem hacmi Vmax. başlangıç durumuna geri döner.

Bu düzenleme sonucunda oluşan denge eğrisi şekil 1'in alt kısmında gösterilmiştir. B1 durumundan B2 durumuna olan ilk düşüşün azaldığını ve B1 durumundan B2* durumuna düştüğünü görebilirsiniz. Ayrıca, maksimum hacmin Т8...Т10 geri kazanıldığı süre içinde karın biraz düştüğünü de gözlemleyebilirsiniz - bu, madalyonun öteki yüzüdür.

Yeşil renk, minimum belirtilen hacimle alım satım işlemi yapıldığında denge eğrisinin bir kısmını vurgular. Sarı renk, maksimumdan minimum hacme ve geriye doğru geçiş kısımlarını temsil eder. Burada birkaç geçiş varyantı mümkündür:

  • Kademeli - Hacim maksimumdan minimum hacme ve geriye doğru ayrı adımlarla değişir,
  • Doğrusal - Hacim, düzenlenmiş aralık içinde denge eğrisinin eğim açısına bağlı olarak doğrusal olarak değiştirilir,
  • Histerezisli kademeli - Maksimumdan minimum hacme ve geriye doğru geçiş, eğim açısının fark değerlerinde gerçekleştirilir.

Bunu resimlerle gösterelim:

Düzenleyici özellik türleri

Şekil 2. Düzenleyici özellik türleri

Düzenleyici özellikler, kontrol sisteminin hızını etkiler - Etkinleştirme/devre dışı bırakma gecikmesi, maksimumdan minimum hacme geçiş ve geriye doğru geçiş süreci. En iyi test sonuçlarına ulaşılırken deneysel olarak bir özellik seçilmesi önerilir.

Böylece, denge eğrisinin eğim açısına dayalı geri bildirim ile alım satım sistemini geliştiriyoruz. Bu tür bir hacim düzenlemesinin, yalnızca alım satım sisteminin bir parçası olarak hacme sahip olmayan sistemler için uygun olduğunu unutmayın. Örneğin, Martingale prensibi kullanılıyorsa ilk Expert Advisor'da değişiklik yapmadan bu sistemi doğrudan kullanamazsınız.

Ayrıca, şu önemli noktalara da dikkatimizi çekmemiz gerekiyor:

  • Denge çizgisinin eğimini yönetmenin etkinliği doğrudan normal çalışma modundaki iş hacminin hacim reddetme modundaki hacme oranına bağlıdır. Bu oran ne kadar büyük olursa, yönetim o kadar etkili olur. Bu nedenle, başlangıçtaki iş hacmi, mümkün olan minimum hacimden çok daha büyük olmalıdır.
  • Expert Advisor dengesinin ortalama yükselme ve düşme değişim dönemi, kontrol sisteminin tepki verme süresinden oldukça büyük olmalıdır. Aksi takdirde, sistem denge eğrisinin eğimini düzenlemeyi başaramayacaktır. Ortalama sürenin tepki süresine oranı ne kadar fazlaysa sistem o kadar etkilidir. Bu gereklilik hemen hemen her otomatik düzenleme sistemini ilgilendirmektedir.

Nesne Yönelimli Programlama Kullanarak MQL5'te Uygulama

Yukarıda anlatılan yaklaşımı gerçekleştiren bir kitaplık yazalım. Bunu yapmak için, MQL5'in yeni özelliği olan nesne yönelimli yaklaşımı kullanalım. Bu yaklaşım, kodun büyük bölümlerini sıfırdan yeniden yazmadan gelecekte kitaplığımızı kolayca geliştirmemize ve genişletmemize olanak tanır.


TradeSymbol Sınıfı

Çoklu para birimi testi yeni MetaTrader 5 platformunda uygulandığı için tüm çalışmayı kendi içinde herhangi bir iş sembolü ile kapsayan bir sınıfa ihtiyacımız var. Bu, söz konusu kitaplığın çok para birimli Expert Advisor'larda kullanılmasına izin verir. Bu sınıf, kontrol sistemini doğrudan ilgilendirmez; yardımcıdır. Bu nedenle, bu sınıf, iş sembolü ile işlemler için kullanılacaktır.

//---------------------------------------------------------------------
//  Operations with work symbol:
//---------------------------------------------------------------------
class TradeSymbol
{
private:
  string  trade_symbol;                          // work symbol

private:
  double  min_trade_volume;                      // minimum allowed volume for trade operations
  double  max_trade_volume;                      // maximum allowed volume for trade operations
  double  min_trade_volume_step;                 // minimum change of volume
  double  max_total_volume;                      // maximum change of volume
  double  symbol_point;                          // size of one point
  double  symbol_tick_size;                      // minimum change of price
  int     symbol_digits;                        // number of digits after decimal point

protected:

public:
  void    RefreshSymbolInfo( );                  // refresh market information about the work symbol
  void    SetTradeSymbol( string _symbol );      // set/change work symbol
  string  GetTradeSymbol( );                     // get work symbol
  double  GetMaxTotalLots( );                    // get maximum cumulative volume
  double  GetPoints( double _delta );            // get change of price in points

public:
  double  NormalizeLots( double _requied_lot );  // get normalized trade volume
  double  NormalizePrice( double _org_price );   // get normalized price with consideration of step of change of quote

public:
  void    TradeSymbol( );                       // constructor
  void    ~TradeSymbol( );                      // destructor
};

Sınıfın yapısı çok basittir. Amaç, mevcut piyasa bilgilerinin belirli bir sembol ile alınması, saklanması ve işlenmesidir. Ana yöntemler şu şekildedir: TradeSymbol::RefreshSymbolInfo, TradeSymbol::NormalizeLots, TradeSymbol::NormalizePrice. Onları tek tek ele alalım.


TradeSymbol::RefreshSymbolInfo yöntemi, iş sembolü ile piyasa bilgilerini yenilemek için tasarlanmıştır.

//---------------------------------------------------------------------
//  Refresh market information by work symbol:
//---------------------------------------------------------------------
void
TradeSymbol::RefreshSymbolInfo( )
{
//  If a work symbol is not set, don't do anything:
  if( GetTradeSymbol( ) == NULL )
  {
    return;
  }

//  Calculate parameters necessary for normalization of volume:
  min_trade_volume = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_VOLUME_MIN );
  max_trade_volume = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_VOLUME_MAX );
  min_trade_volume_step = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_VOLUME_STEP );

  max_total_volume = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_VOLUME_LIMIT );

  symbol_point = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_POINT );
  symbol_tick_size = SymbolInfoDouble( GetTradeSymbol( ), SYMBOL_TRADE_TICK_SIZE );
  symbol_digits = ( int )SymbolInfoInteger( GetTradeSymbol( ), SYMBOL_DIGITS );
}

Birkaç yöntemde kullanılan önemli bir noktaya dikkat edin. MQL5'in mevcut gerçekleştirilmesi, parametrelerle bir oluşturucu kullanılmasına izin vermediği için iş sembollerinin birincil ayarı için şu yöntemi çağırmalısınız:

void    SetTradeSymbol( string _symbol );      // set/change work symbol


TradeSymbol::NormalizeLots yöntemi, doğru ve normalize edilmiş bir hacim elde etmek için kullanılır. Bir pozisyonun boyutunun, aracı tarafından izin verilen minimum olası değerden daha küçük olamayacağını biliyoruz. Bir pozisyonun minimum değişim adımı da aracı tarafından belirlenir ve farklılık gösterebilir. Bu yöntem, alttan en yakın hacim değerini döndürür.

Ayrıca, varsayılan pozisyonun hacminin, aracı tarafından izin verilen maksimum değeri aşıp aşmadığını da kontrol eder.

//---------------------------------------------------------------------
//  Get normalized trade volume:
//---------------------------------------------------------------------
//  - input necessary volume;
//  - output is normalized volume;
//---------------------------------------------------------------------
double
TradeSymbol::NormalizeLots( double _requied_lots )
{
  double   lots, koeff;
  int      nmbr;

//  If a work symbol is not set, don't do anything:
  if( GetTradeSymbol( ) == NULL )
  {
    return( 0.0 );
  }

  if( this.min_trade_volume_step > 0.0 )
  {
    koeff = 1.0 / min_trade_volume_step;
    nmbr = ( int )MathLog10( koeff );
  }
  else
  {
    koeff = 1.0 / min_trade_volume;
    nmbr = 2;
  }
  lots = MathFloor( _requied_lots * koeff ) / koeff;

//  Lower limit of volume:
  if( lots < min_trade_volume )
  {
    lots = min_trade_volume;
  }

//  Upper limit of volume:
  if( lots > max_trade_volume )
  {
    lots = max_trade_volume;
  }

  lots = NormalizeDouble( lots, nmbr );
  return( lots );
}


TradeSymbol::NormalizePrice yöntemi, doğru ve normalize edilmiş fiyatı elde etmek için kullanılır. Belirli bir sembol için ondalık noktadan sonraki anlamlı basamak sayısı (fiyatın doğruluğu) belirlenmek zorunda olduğu için fiyatı kısaltmamız gerekir. Buna ek olarak, bazı semboller (örneğin, vadeli işlemler) bir noktadan daha büyük bir minimum fiyat değişikliği adımına sahiptir. Bu nedenle fiyat değerlerini minimum tutarsızlığın katı yapmalıyız.

//---------------------------------------------------------------------
//  Normalization of price with consideration of step of price change:
//---------------------------------------------------------------------
double
TradeSymbol::NormalizePrice( double _org_price )
{
//  Minimal step of quote change in points:
  double  min_price_step = NormalizeDouble( symbol_tick_size / symbol_point, 0 );

  double  norm_price = NormalizeDouble( NormalizeDouble(( NormalizeDouble( _org_price / symbol_point, 0 )) / min_price_step, 0 ) * min_price_step * symbol_point, symbol_digits );
  return( norm_price );
}

Gerekli normalize edilmemiş fiyat, işleve girilir. Ve gerekli olana en yakın olan normalize edilmiş fiyatı döndürür.

Diğer yöntemlerin amacı yorumlarda açıkça anlatılmıştır; daha fazla açıklama gerektirmez.


TBalanceHistory Sınıfı

Bu sınıf, adından da anlaşılacağı gibi bir hesabın bakiye geçmişi ile çalışmak için tasarlanmıştır. Ayrıca aşağıda açıklanan birkaç sınıf için bir temel sınıftır. Bu sınıfın temel amacı, bir Expert Advisor'ın alım satım geçmişine erişim sağlamaktır. Ayrıca, geçmişi iş sembolüne, "sihirli sayıya", Expert Advisor'ın izlenmeye başlandığı tarihe veya aynı anda üç öğeye göre filtreleyebilirsiniz.

//---------------------------------------------------------------------
//  Operations with balance history:
//---------------------------------------------------------------------
class TBalanceHistory
{
private:
  long      current_magic;            // value of "magic number" when accessing the history of deals ( 0 - any number )
  long      current_type;             // type of deals ( -1 - all )
  int       current_limit_history;   // limit of depth of history ( 0 - all history )
  datetime   monitoring_begin_date;   // date of start of monitoring history of deals
  int       real_trades;             // number of actual trades already performed

protected:
  TradeSymbol  trade_symbol;          // operations with work symbol

protected:
//  "Raw" arrays:
  double    org_datetime_array[ ];    // date/time of trade
  double    org_result_array[ ];      // result of trade

//  Arrays with data grouped by time:
  double    group_datetime_array[ ];  // date/time of trade
  double    group_result_array[ ];    // result of trade

  double    last_result_array[ ];     // array for storing results of last trades ( points on the Y axis )
  double    last_datetime_array[ ];   // array for storing time of last trades ( points on the X axis )

private:
  void      SortMasterSlaveArray( double& _m[ ], double& _s[ ] );  // synchronous ascending sorting of two arrays

public:
  void      SetTradeSymbol( string _symbol );                      // set/change work symbol
  string    GetTradeSymbol( );                                    // get work symbol
  void      RefreshSymbolInfo( );                                 // refresh market information by work symbol
  void      SetMonitoringBeginDate( datetime _dt );                // set date of start of monitoring
  datetime  GetMonitoringBeginDate( );                            // get date of start of monitoring
  void      SetFiltrParams( long _magic, long _type = -1, int _limit = 0 );// set parameters of filtration of deals

public:
// Get results of last trades:
  int       GetTradeResultsArray( int _max_trades );

public:
  void      TBalanceHistory( );       // constructor
  void      ~TBalanceHistory( );      // destructor
};

Son alım satım işlemlerinin ve geçmişin sonuçlarını okurken filtreleme ayarları, TBalanceHistory::SetFiltrParams yöntemi kullanılarak belirlenir. Bu, aşağıdaki giriş parametrelerine sahiptir:

  • _magic           - Geçmişten okunması gereken alım satım işlemlerinin "sihirli sayısı". Sıfır değeri belirtilirse herhangi bir "sihirli sayı" içeren alım satım işlemleri okunacaktır.
  • _type             - Okunması gereken yatırımların türü. Şu değerleri içerebilir: DEAL_TYPE_BUY (yalnızca uzun alım satım işlemlerini okumak için), DEAL_TYPE_SELL (yalnızca kısa alım satım işlemlerini okumak için) ve - 1 (hem uzun hem de kısa alım satım işlemlerini okumak için).
  • _limit             - Analiz edilen alım satım işlemlerinin derinliğini sınırlar. Sıfıra eşitse mevcut tüm geçmiş analiz edilir.

Varsayılan olarak, TBalanceHistory sınıfının nesnesi oluşturulduğunda şu değerler ayarlanır: _magic = 0, _type = -1, _limit = 0.


Bu sınıfın ana yöntemi şu şekildedir: TBalanceHistory::GetTradeResultsArray. last_result_array ve last_datetime_array sınıf üye dizilerini son alım satım işlemlerinin sonuçlarıyla doldurmak için tasarlanmıştır. Yöntem, şu giriş parametrelerine sahiptir:

  • _max_trades - Geçmişten okunması ve çıktı dizilerine yazılması gereken maksimum alım satım işlemi sayısı. Eğim açısını hesaplamak için en az iki noktaya ihtiyacımız olduğu için bu değer ikiden küçük olmamalıdır. Bu değer sıfıra eşitse mevcut tüm alım satım işlemi geçmişi analiz edilir. Pratik olarak, denge eğrisinin eğiminin hesaplanması için gerekli nokta sayısı burada belirtilir.
//---------------------------------------------------------------------
//  Reads the results of last (by time) trades to arrays:
//---------------------------------------------------------------------
//  - returns the number of actually read trades but not more than specified;
//---------------------------------------------------------------------
int
TBalanceHistory::GetTradeResultsArray( int _max_trades )
{
  int       index, limit, count;
  long      deal_type, deal_magic, deal_entry;
  datetime   deal_close_time, current_time;
  ulong     deal_ticket;                        // ticket of deal
  double    trade_result;
  string    symbol, deal_symbol;

  real_trades = 0;

//  Number of trades should be no less than two:
  if( _max_trades < 2 )
  {
    return( 0 );
  }

//  If a work symbol is not specified, don't do anything:
  symbol = trade_symbol.GetTradeSymbol( );
  if( symbol == NULL )
  {
    return( 0 );
  }

//  Request the history of deals and orders from the specified time to the current moment:
  if( HistorySelect( monitoring_begin_date, TimeCurrent( )) != true )
  {
    return( 0 );
  }

//  Calculate number of trades:
  count = HistoryDealsTotal( );

//  If there are less trades in the history than it is necessary, then exit:
  if( count < _max_trades )
  {
    return( 0 );
  }

//  If there are more trades in the history than it is necessary, then limit them:
  if( current_limit_history > 0 && count > current_limit_history )
  {
    limit = count - current_limit_history;
  }
  else
  {
    limit = 0;
  }

//  If needed, adjust dimension of "raw" arrays by the specified number of trades:
  if(( ArraySize( org_datetime_array )) != ( count - limit ))
  {
    ArrayResize( org_datetime_array, count - limit );
    ArrayResize( org_result_array, count - limit );
  }

//  Fill the "raw" array with trades from history base:
  real_trades = 0;
  for( index = count - 1; index >= limit; index-- )
  {
    deal_ticket = HistoryDealGetTicket( index );

//  If those are not closed deals, don't go further:
    deal_entry = HistoryDealGetInteger( deal_ticket, DEAL_ENTRY );
    if( deal_entry != DEAL_ENTRY_OUT )
    {
      continue;
    }

//  Check "magic number" of deal if necessary:
    deal_magic = HistoryDealGetInteger( deal_ticket, DEAL_MAGIC );
    if( current_magic != 0 && deal_magic != current_magic )
    {
      continue;
    }

//  Check symbol of deal:
    deal_symbol = HistoryDealGetString( deal_ticket, DEAL_SYMBOL );
    if( symbol != deal_symbol )
    {
      continue;
    }
                
//  Check type of deal if necessary:
    deal_type = HistoryDealGetInteger( deal_ticket, DEAL_TYPE );
    if( current_type != -1 && deal_type != current_type )
    {
      continue;
    }
    else if( current_type == -1 && ( deal_type != DEAL_TYPE_BUY && deal_type != DEAL_TYPE_SELL ))
    {
      continue;
    }
                
//  Check time of closing of deal:
    deal_close_time = ( datetime )HistoryDealGetInteger( deal_ticket, DEAL_TIME );
    if( deal_close_time < monitoring_begin_date )
    {
      continue;
    }

//  So, we can read another trade:
    org_datetime_array[ real_trades ] = deal_close_time / 60;
    org_result_array[ real_trades ] = HistoryDealGetDouble( deal_ticket, DEAL_PROFIT ) / HistoryDealGetDouble( deal_ticket, DEAL_VOLUME );
    real_trades++;
  }

//  if there are less trades than necessary, return:
  if( real_trades < _max_trades )
  {
    return( 0 );
  }

  count = real_trades;

//  Sort the "raw" array by date/time of closing the order:
  SortMasterSlaveArray( org_datetime_array, org_result_array );

// If necessary, adjust dimension of group arrays for the specified number of points:
  if(( ArraySize( group_datetime_array )) != count )
  {
    ArrayResize( group_datetime_array, count );
    ArrayResize( group_result_array, count );
  }
  ArrayInitialize( group_datetime_array, 0.0 );
  ArrayInitialize( group_result_array, 0.0 );

//  Fill the output array with grouped data ( group by the identity of date/time of position closing ):
  for( index = 0; index < count; index++ )
  {
//  Get another trade:
    deal_close_time = ( datetime )org_datetime_array[ index ];
    trade_result = org_result_array[ index ];

//  Now check if the same time already exists in the output array:
    current_time = ( datetime )group_datetime_array[ real_trades ];
    if( current_time > 0 && MathAbs( current_time - deal_close_time ) > 0.0 )
    {
      real_trades++;                      // move the pointer to the next element
      group_result_array[ real_trades ] = trade_result;
      group_datetime_array[ real_trades ] = deal_close_time;
    }
    else
    {
      group_result_array[ real_trades ] += trade_result;
      group_datetime_array[ real_trades ] = deal_close_time;
    }
  }
  real_trades++;                          // now this is the number of unique elements

//  If there are less trades than necessary, exit:
  if( real_trades < _max_trades )
  {
    return( 0 );
  }

  if( ArraySize( last_result_array ) != _max_trades )
  {
    ArrayResize( last_result_array, _max_trades );
    ArrayResize( last_datetime_array, _max_trades );
  }

//  Write the accumulated data to the output arrays with reversed indexation:
  for( index = 0; index < _max_trades; index++ )
  {
    last_result_array[ _max_trades - 1 - index ] = group_result_array[ index ];
    last_datetime_array[ _max_trades - 1 - index ] = group_datetime_array[ index ];
  }

//  In the output array replace the results of single trades with the accumulating total:
  for( index = 1; index < _max_trades; index++ )
  {
    last_result_array[ index ] += last_result_array[ index - 1 ];
  }

  return( _max_trades );
}

Başlangıçta - bir iş sembolü belirtilmişse ve giriş parametreleri doğruysa - zorunlu kontroller yapılır.

Daha sonra, belirtilen tarihten şu ana kadar olan yatırımların ve talimatların geçmişini okuyoruz. Bu, kodun aşağıdaki bölümünde gerçekleştirilir:

//  Request the history of deals and orders from the specified time to the current moment:
  if( HistorySelect( monitoring_begin_date, TimeCurrent( )) != true )
  {
    return( 0 );
  }

//  Calculate number of trades:
  count = HistoryDealsTotal( );

//  If there are less trades in the history than it is necessary, then exit:
  if( count < _max_trades )
  {
    return( 0 );
  }

Ayrıca, geçmişteki toplam yatırım sayısı kontrol edilir. Belirtilenden daha azsa, diğer eylemler anlamsızdır. "İşlenmemiş" diziler hazırlanır hazırlanmaz, bunları alım satım işlemi geçmişinden gelen bilgilerle doldurma döngüsü yürütülür. Bu, şu şekilde yapılır:

//  Fill the "raw" array from the base of history of trades:
  real_trades = 0;
  for( index = count - 1; index >= limit; index-- )
  {
    deal_ticket = HistoryDealGetTicket( index );

//  If the trades are not closed, don't go further:
    deal_entry = HistoryDealGetInteger( deal_ticket, DEAL_ENTRY );
    if( deal_entry != DEAL_ENTRY_OUT )
    {
      continue;
    }

//  Check "magic number" of deal if necessary:
    deal_magic = HistoryDealGetInteger( deal_ticket, DEAL_MAGIC );
    if( _magic != 0 && deal_magic != _magic )
    {
      continue;
    }

//  Check symbols of deal:
    deal_symbol = HistoryDealGetString( deal_ticket, DEAL_SYMBOL );
    if( symbol != deal_symbol )
    {
      continue;
    }
                
//  Check type of deal if necessary:
    deal_type = HistoryDealGetInteger( deal_ticket, DEAL_TYPE );
    if( _type != -1 && deal_type != _type )
    {
      continue;
    }
    else if( _type == -1 && ( deal_type != DEAL_TYPE_BUY && deal_type != DEAL_TYPE_SELL ))
    {
      continue;
    }
                
//  Check time of closing of deal:
    deal_close_time = ( datetime )HistoryDealGetInteger( deal_ticket, DEAL_TIME );
    if( deal_close_time < monitoring_begin_date )
    {
      continue;
    }

//  So, we can rad another trade:
    org_datetime_array[ real_trades ] = deal_close_time / 60;
    org_result_array[ real_trades ] = HistoryDealGetDouble( deal_ticket, DEAL_PROFIT ) / HistoryDealGetDouble( deal_ticket, DEAL_VOLUME );
    real_trades++;
  }

//  If there are less trades than necessary, exit:
  if( real_trades < _max_trades )
  {
    return( 0 );
  }

Başlangıçta, geçmişteki yatırım bileti HistoryDealGetTicket işlevi kullanılarak okunur, yatırım ayrıntılarının daha fazla okunması, elde edilen bilet kullanılarak gerçekleştirilir. Yalnızca kapalı alım satım işlemleriyle ilgilendiğimiz için (bakiyeyi analiz edeceğiz), önce yatırımın türü kontrol edilir. Bu, DEAL_ENTRY parametresi ile HistoryDealGetInteger işlevi çağrılarak yapılır. İşlev DEAL_ENTRY_OUT öğesini döndürürse, bir pozisyonu kapatıyor demektir.

Bunun ardından yatırımın "sihirli sayısı", yatırımın türü (yöntemin giriş parametresi belirtilir) ve yatırımın sembolü kontrol edilir. Yatırımın tüm parametreleri gereklilikleri karşılıyorsa son parametre kontrol edilir - yatırımın kapanış zamanı. Bu, şu şekilde yapılır:

//  Check the time of closing of deal:
    deal_close_time = ( datetime )HistoryDealGetInteger( deal_ticket, DEAL_TIME );
    if( deal_close_time < monitoring_begin_date )
    {
      continue;
    }

Yatırımın tarihi/saati, geçmişi izlemenin başlangıç tarihi/saati ile karşılaştırılır. Yatırımın tarihi/saati verilenden büyükse, o zaman alım satım işlemimizi diziye okumaya gideriz - Alım satım işleminin sonucunu puan cinsinden ve alım satım işleminin saatini dakika cinsinden okuyun (bu durumda, kapanış zamanı). Bundan sonra, real_trades yatırımlarını okuma sayacı artar ve döngü devam eder.

"İşlenmemiş" diziler gerekli miktarda bilgi ile doldurulduktan sonra, yatırımların kapanış zamanının saklandığı diziyi sıralamalıyız. Aynı zamanda, org_datetime_array dizisindeki kapanış zamanının ve org_result_array dizisindeki yatırımların sonuçlarının yazışmalarını tutmamız gerekiyor. Bu, özel olarak yazılmış yöntem kullanılarak yapılır:

TBalanceHistory::SortMasterSlaveArray( double& _master[ ], double& _slave[ ] ). İlk parametre _master - artan şekilde sıralanan dizidir. İkinci parametre _slave - öğelerinin birinci dizinin öğeleriyle eşzamanlı olarak taşınması gereken dizidir. Sıralama "kabarcık" yöntemiyle yapılır.

Yukarıda açıklanan tüm işlemlerden sonra, zamana ve zamana göre sıralanmış yatırımların sonuçlarını içeren iki diziye sahip oluruz. Denge eğrisi üzerinde yalnızca bir nokta (Y ekseni üzerindeki nokta) zamanın her anına (X eksenindeki nokta) karşılık gelebileceği için dizinin öğelerini aynı kapanış zamanı ile (varsa) gruplandırmamız gerekir. Bu işlemi, kodun aşağıdaki kısmı gerçekleştirir:

//  Fill the output array with grouped data ( group by identity of date/time of closing of position ):
  real_trades = 0;
  for( index = 0; index < count; index++ )
  {
//  Get another trade:
    deal_close_time = ( datetime )org_datetime_array[ index ];
    trade_result = org_result_array[ index ];

//  Now check, if the same time already exists in the output array:
    current_time = ( datetime )group_datetime_array[ real_trades ];
    if( current_time > 0 && MathAbs( current_time - deal_close_time ) > 0.0 )
    {
      real_trades++;                      // move the pointer to the next element
      group_result_array[ real_trades ] = trade_result;
      group_datetime_array[ real_trades ] = deal_close_time;
    }
    else
    {
      group_result_array[ real_trades ] += trade_result;
      group_datetime_array[ real_trades ] = deal_close_time;
    }
  }
  real_trades++;                          // now this is the number of unique elements

Pratik olarak, "aynı" kapanış zamanına sahip tüm alım satım işlemleri burada toplanır. Sonuçlar, TBalanceHistory::group_datetime_array (kapanış zamanı) ve TBalanceHistory::group_result_array (alım satım işlemlerinin sonuçları) dizilerine yazılır. Bunun ardından, benzersiz öğelere sahip iki sıralı dizi elde ederiz. Bu durumda zamanın kimliği bir dakika içinde kabul edilir. Bu dönüşüm, grafiksel olarak gösterilebilir:

Aynı zamana göre gruplandırma

Şekil 3. Yatırımları aynı zamana göre gruplandırma

Bir dakika içindeki tüm yatırımlar (şekildeki sol kısım), zamanın yuvarlanması ve sonuçların toplanmasıyla (şekildeki sağ kısım) tek bir işlemde gruplandırılır. Bu, yatırımların kapanış zamanının "yüksek perdeden çıkan sesini" yumuşatmaya ve düzenlemenin istikrarını iyileştirmeye olanak tanır.

Bundan sonra, elde edilen dizilerin iki dönüşümünü daha yapmanız gerekir. En erken yatırımın sıfır öğeye karşılık gelmesi için öğelerin sırasını tersine çevirin ve tekli alım satım işlemlerinin sonuçlarını kümülatif toplamla, yani bakiyeyle değiştirin. Bu, kodun aşağıdaki parçasında yapılır:

//  Write the accumulated data into output arrays with reversed indexation:
  for( index = 0; index < _max_trades; index++ )
  {
    last_result_array[ _max_trades - 1 - index ] = group_result_array[ index ];
    last_datetime_array[ _max_trades - 1 - index ] = group_datetime_array[ index ];
  }

//  Replace the results of single trades with the cumulative total in the output array:
  for( index = 1; index < _max_trades; index++ )
  {
    last_result_array[ index ] += last_result_array[ index - 1 ];
  }


TBalanceSlope Sınıfı

Bu sınıf, bir hesabın denge eğrisi ile işlem yapmak için tasarlanmıştır. TBalanceHistory sınıfından oluşturulur ve tüm korumalı ve herkese açık verilerini ve yöntemlerini devralır. Yapısına ayrıntılı bir şekilde göz atalım:

//---------------------------------------------------------------------
//  Operations with the balance curve:
//---------------------------------------------------------------------
class TBalanceSlope : public TBalanceHistory
{
private:
  double    current_slope;               // current angle of slope of the balance curve
  int       slope_count_points;          // number of points ( trades ) for calculation of slope angle
        
private:
  double    LR_koeff_A, LR_koeff_B;      // rates for the equation of the straight-line regression
  double    LR_points_array[ ];          // array of point of the straight-line regression

private:
  void      CalcLR( double& X[ ], double& Y[ ] );  // calculate the equation of the straight-line regression

public:
  void      SetSlopePoints( int _number );        // set the number of points for calculation of angle of slope
  double    CalcSlope( );                         // calculate the slope angle

public:
  void      TBalanceSlope( );                     // constructor
  void      ~TBalanceSlope( );                    // destructor
};


Denge eğrisi üzerinde belirtilen puan (alım satım işlemleri) miktarı için çizilen doğrusal regresyon çizgisinin eğim açısı ile denge eğrisinin eğim açısını belirleyeceğiz. Bu nedenle, her şeyden önce, aşağıdaki formun doğrusal regresyon denklemini hesaplamamız gerekir: A*x + B. Bu iş, aşağıdaki yöntemle gerçekleştirilir:

//---------------------------------------------------------------------
//  Calculate the equation of the straight-line regression:
//---------------------------------------------------------------------
//  input parameters:
//    X[ ] - arras of values of number series on the X axis;
//    Y[ ] - arras of values of number series on the Y axis;
//---------------------------------------------------------------------
void
TBalanceSlope::CalcLR( double& X[ ], double& Y[ ] )
{
  double    mo_X = 0, mo_Y = 0, var_0 = 0, var_1 = 0;
  int       i;
  int       size = ArraySize( X );
  double    nmb = ( double )size;

//  If the number of points is less than two, the curve cannot be calculated:
  if( size < 2 )
  {
    return;
  }

  for( i = 0; i < size; i++ )
  {
    mo_X += X[ i ];
    mo_Y += Y[ i ];
  }
  mo_X /= nmb;
  mo_Y /= nmb;

  for( i = 0; i < size; i++ )
  {
    var_0 += ( X[ i ] - mo_X ) * ( Y[ i ] - mo_Y );
    var_1 += ( X[ i ] - mo_X ) * ( X[ i ] - mo_X );
  }

//  Value of the A coefficient:
  if( var_1 != 0.0 )
  {
    LR_koeff_A = var_0 / var_1;
  }
  else
  {
    LR_koeff_A = 0.0;
  }

//  Value of the B coefficient:
  LR_koeff_B = mo_Y - LR_koeff_A * mo_X;

//  Fill the array of points that lie on the regression line:
  ArrayResize( LR_points_array, size );
  for( i = 0; i < size; i++ )
  {
    LR_points_array[ i ] = LR_koeff_A * X[ i ] + LR_koeff_B;
  }
}

Burada, ilk verilere göre regresyon çizgisinin minimum pozisyon hatasını hesaplamak için en küçük kareler yöntemini kullanıyoruz. Hesaplanan doğru üzerinde bulunan Y koordinatlarını saklayan dizi de doldurulur. Bu dizi şu anda kullanılmamaktadır ve daha fazla geliştirme amaçlıdır.


Verilen sınıfta kullanılan ana yöntem şu şekildedir: TBalanceSlope::CalcSlope. Bu, belirtilen son alım satım işlemi miktarı ile hesaplanan denge eğrisinin eğim açısını döndürür. Bunun ne şekilde gerçekleştiğine bakalım:

//---------------------------------------------------------------------
//  Calculate slope angle:
//---------------------------------------------------------------------
double
TBalanceSlope::CalcSlope( )
{
//  Get result of trading from the history of trades:
  int      nmb = GetTradeResultsArray( slope_count_points );
  if( nmb < slope_count_points )
  {
    return( 0.0 );
  }

//  Calculate the regression line by the results of last trades:
  CalcLR( last_datetime_array, last_result_array );
  current_slope = LR_koeff_A;

  return( current_slope );
}

İlk olarak, denge eğrisinin belirlenen son noktalarının miktarı analiz edilir. Bu, TBalanceSlope::GetTradeResultsArray temel sınıfının yöntemi çağrılarak yapılır. Okuma noktalarının miktarı belirtilenden az değilse regresyon çizgisi hesaplanır. Bu, TBalanceSlope::CalcLR yöntemi kullanılarak yapılır. Bir önceki adımda doldurulan, temel sınıfa ait last_result_array ve last_datetime_array dizileri argümanlar olarak kullanılır.

Geri kalan yöntemler basittir ve ayrıntılı bir açıklama gerektirmez.


TBalanceSlopeControl Sınıfı

İş hacmini değiştirerek denge eğrisinin eğimini yöneten temel sınıftır. TBalanceSlope sınıfından oluşturulur ve tüm genel ve korumalı yöntemlerini ve verilerini devralır. Bu sınıfın tek amacı, denge eğrisinin mevcut eğim açısına bağlı olarak mevcut iş hacmini hesaplamaktır. Şimdi bunu ayrıntılı bir şekilde inceleyelim:

//---------------------------------------------------------------------
//  Managing slope of the balance curve:
//---------------------------------------------------------------------
enum LotsState
{
  LOTS_NORMAL = 1,            // mode of trading with normal volume
  LOTS_REJECTED = -1,         // mode of trading with lowered volume
  LOTS_INTERMEDIATE = 0,      // mode of trading with intermediate volume
};
//---------------------------------------------------------------------
class TBalanceSlopeControl : public TBalanceSlope
{
private:
  double    min_slope;          // slope angle that corresponds to the mode of volume rejection
  double    max_slope;          // slope angle that corresponds to the mode of normal volume
  double    centr_slope;        // slope angle that corresponds to the mode of volume switching without hysteresis

private:
  ControlType  control_type;    // type of the regulation function

private:
  double    rejected_lots;      // volume in the rejection mode
  double    normal_lots;        // volume in the normal mode
  double    intermed_lots;      // volume in the intermediate mode

private:
  LotsState current_lots_state; // current mode of volume

public:
  void      SetControlType( ControlType _control );  // set type of the regulation characteristic
  void      SetControlParams( double _min_slope, double _max_slope, double _centr_slope );

public:
  double    CalcTradeLots( double _min_lots, double _max_lots );  // get trade volume

protected:
  double    CalcIntermediateLots( double _min_lots, double _max_lots, double _slope );

public:
  void      TBalanceSlopeControl( );   // constructor
  void      ~TBalanceSlopeControl( );  // destructor
};


Mevcut hacmi hesaplamadan önce, başlangıç parametrelerini ayarlamamız gerekir. Bu, aşağıdaki yöntemler çağrılarak yapılır:

  void      SetControlType( ControlType _control );  // set type of the regulation characteristic

Giriş parametresi_control - bu, düzenleme özelliğinin türüdür. Aşağıdaki değere sahip olabilir:

  • STEP_WITH_HYSTERESISH      - Histerezisli kademeli düzenleme özelliği,
  • STEP_WITHOUT_HYSTERESIS  - Histerezissiz kademeli düzenleme özelliği,
  • LINEAR                                   - Doğrusal düzenleme özelliği,
  • NON_LINEAR                           - Doğrusal olmayan düzenleme özelliği (bu sürümde uygulanmamıştır).


  void      SetControlParams( double _min_slope, double _max_slope, double _centr_slope );

Giriş parametreleri şu şekildedir:

  • _min_slope - Minimum hacimle alım satıma karşılık gelen denge eğrisinin eğim açısı,
  • _max_slope - Maksimum hacimle alım satıma karşılık gelen denge eğrisinin eğim açısı,
  • _centr_slope - Histerezissiz kademeli düzenleme özelliğine karşılık gelen denge eğrisinin eğim açısı.


Hacim, aşağıdaki yöntem kullanılarak hesaplanır:

//---------------------------------------------------------------------
//  Get trade volume:
//---------------------------------------------------------------------
double
TBalanceSlopeControl::CalcTradeLots( double _min_lots, double _max_lots )
{
//  Try to calculate slope of the balance curve:
  double    current_slope = CalcSlope( );

//  If the specified amount of trades is not accumulated yet, trade with minimal volume:
  if( GetRealTrades( ) < GetSlopePoints( ))
  {
    current_lots_state = LOTS_REJECTED;
    rejected_lots = trade_symbol.NormalizeLots( _min_lots );
    return( rejected_lots );
  }

//  If the regulation function is stepped without hysteresis:
  if( control_type == STEP_WITHOUT_HYSTERESIS )
  {
    if( current_slope < centr_slope )
    {
      current_lots_state = LOTS_REJECTED;
      rejected_lots = trade_symbol.NormalizeLots( _min_lots );
      return( rejected_lots );
    }
    else
    {
      current_lots_state = LOTS_NORMAL;
      normal_lots = trade_symbol.NormalizeLots( _max_lots );
      return( normal_lots );
    }
  }

//  If the slope of linear regression for the balance curve is less than the allowed one:
  if( current_slope < min_slope )
  {
    current_lots_state = LOTS_REJECTED;
    rejected_lots = trade_symbol.NormalizeLots( _min_lots );
    return( rejected_lots );
  }

//  If the slope of linear regression for the balance curve is greater than specified:
  if( current_slope > max_slope )
  {
    current_lots_state = LOTS_NORMAL;
    normal_lots = trade_symbol.NormalizeLots( _max_lots );
    return( normal_lots );
  }

//  The slope of linear regression for the balance curve is within specified borders (intermediate state):
  current_lots_state = LOTS_INTERMEDIATE;

//  Calculate the value of intermediate volume:
  intermed_lots = CalcIntermediateLots( _min_lots, _max_lots, current_slope );
  intermed_lots = trade_symbol.NormalizeLots( intermed_lots );

  return( intermed_lots );
}

TBalanceSlopeControl::CalcTradeLots yönteminin uygulanmasının başlıca önemli noktaları şu şekildedir:

  • Belirtilen minimum alım satım işlemi miktarı birikene kadar, minimum hacimle alım satım yapın. Bu mantıklıdır; zira Expert Advisor'ın alım satım işlemi için ayarladıktan hemen sonra hangi dönemde (karlı veya değil) olduğu bilinmiyor.
  • Düzenleme işlevi histerezissiz bir adımsa alım satım modları arasında geçiş açısını TBalanceSlopeControl::SetControlParams yöntemiyle ayarlamak için yalnızca _centr_slope parametresini kullanmalısınız. _min_slope ve _max_slope parametreleri yok sayılır. Bu, MetaTrader 5 strateji test cihazında bu parametre ile doğru optimizasyonu gerçekleştirmek için yapılır.

Hesaplanan eğim açısına bağlı olarak minimum, maksimum veya ara hacimde alım satım yapılır. Ara hacim basit yöntemle hesaplanır - TBalanceSlopeControl::CalcIntermediateLots. Bu yöntem korumalıdır ve sınıf içinde kullanılır. Kodu aşağıda gösterilmiştir:

//---------------------------------------------------------------------
//  Calculation of intermediate volume:
//---------------------------------------------------------------------
double
TBalanceSlopeControl::CalcIntermediateLots( double _min_lots, double _max_lots, double _slope )
{
  double    lots;

//  If the regulation function is stepped with hysteresis:
  if( control_type == STEP_WITH_HYSTERESISH )
  {
    if( current_lots_state == LOTS_REJECTED && _slope > min_slope && _slope < max_slope )
    {
      lots = _min_lots;
    }
    else if( current_lots_state == LOTS_NORMAL && _slope > min_slope && _slope < max_slope )
    {
      lots = _max_lots;
    }
  }
//  If the regulation function is linear:
  else if( control_type == LINEAR )
  {
    double  a = ( _max_lots - _min_lots ) / ( max_slope - min_slope );
    double  b = normal_lots - a * .max_slope;
    lots = a * _slope + b;
  }
//  If the regulation function is non-linear ( not implemented yet ):
  else if( control_type == NON_LINEAR )
  {
    lots = _min_lots;
  }
//  If the regulation function is unknown:
  else
  {
    lots = _min_lots;
  }

  return( lots );
}

Bu sınıfın diğer yöntemleri herhangi bir açıklama gerektirmez.


Sistemi Expert Advisor'a Gömme Örneği

Denge eğrisinin eğimini kontrol eden sistemin uygulama sürecini adım adım bir Expert Advisor'da ele alalım.


Adım 1 - Geliştirilen kitaplığı Expert Advisor'a bağlama talimatının eklenmesi:

#include  <BalanceSlopeControl.mqh>


Adım 2 - Denge çizgisinin eğimini kontrol eden sistemin parametrelerinin ayarlanması için harici değişkenleri Expert Advisor'a ekleme:

//---------------------------------------------------------------------
//  Parameters of the system of controlling the slope of the balance curve;
//---------------------------------------------------------------------
enum SetLogic 
{
  No = 0,
  Yes = 1,
};
//---------------------------------------------------------------------
input SetLogic     UseAutoBalanceControl = No;
//---------------------------------------------------------------------
input ControlType  BalanceControlType = STEP_WITHOUT_HYSTERESIS;
//---------------------------------------------------------------------
//  Amount of last trades for calculation of LR of the balance curve:
input int          TradesNumberToCalcLR = 3;
//---------------------------------------------------------------------
//  Slope of LR to decrease the volume to minimum:
input double       LRKoeffForRejectLots = -0.030;
//---------------------------------------------------------------------
//  Slope of LR to restore the normal mode of trading:
input double       LRKoeffForRestoreLots = 0.050;
//---------------------------------------------------------------------
//  Slope of LR to work in the intermediate mode:
input double       LRKoeffForIntermedLots = -0.020;
//---------------------------------------------------------------------
//  Decrease the initial volume to the specified value when the LR is inclined down
input double       RejectedLots = 0.10;
//---------------------------------------------------------------------
//  Normal work volume in the mode of MM with fixed volume:
input double       NormalLots = 1.0;


Adım 3 - TBalanceSlopeControl türünün nesnesini Expert Advisor'a ekleme:

TBalanceSlopeControl  BalanceControl;

Bu bildirim, Expert Advisor'ın başına, işlev tanımlarından önce eklenebilir.


Adım 4 - Expert Advisor'ın OnInit işlevine denge eğrisi kontrol sisteminin başlatılması için kodu ekleme:

//  Adjust our system of controlling the slope of the balance curve:
  BalanceControl.SetTradeSymbol( Symbol( ));
  BalanceControl.SetControlType( BalanceControlType );
  BalanceControl.SetControlParams( LRKoeffForRejectLots, LRKoeffForRestoreLots, LRKoeffForIntermedLots );
  BalanceControl.SetSlopePoints( TradesNumberToCalcLR );
  BalanceControl.SetFiltrParams( 0, -1, 0 );
  BalanceControl.SetMonitoringBeginDate( 0 );


Adım 5 - Expert Advisor'ın OnTick işlevine mevcut piyasa bilgilerini yenilemek için yöntem çağrısını ekleme:

//  Refresh market information:
  BalanceControl.RefreshSymbolInfo( );

Bu yöntemin çağrısı, OnTick işlevinin en başına veya gelen yeni çubuğun kontrolünden sonra (bu kontrole sahip Expert Advisor'lar için) eklenebilir.


Adım 6 - Pozisyonların açıldığı koddan önce mevcut hacim hesaplama kodunu ekleme:

  if( UseAutoBalanceControl == Yes )
  {
    current_lots = BalanceControl.CalcTradeLots( RejectedLots, NormalLots );
  }
  else
  {
    current_lots = NormalLots;
  }

Expert Advisor'da bir Para Yönetimi sistemi kullanılıyorsa o zaman NormalLots yerine TBalanceSlopeControl::CalcTradeLots yöntemini yazmalısınız - Expert Advisor'ın PY sistemi tarafından hesaplanan mevcut hacim.

Yukarıda açıklanan yerleşik sisteme sahip Test Expert Advisor BSCS-TestExpert.mq5 bu makaleye eklenmiştir. Bunun çalışma prensibi, CCI göstergesinin düzeylerinin kesişimine dayanmaktadır. Bu Expert Advisor, test için geliştirilmiştir ve gerçek hesaplar üzerinde çalışmak için uygun değildir. Bunu, EURUSD'nin H4 zaman diliminde (01.07.2008 - 01.09.2010) test edeceğiz.

Bu EA'nın çalışmasının sonucunu analiz edelim. Eğimi kontrol etme sistemi devre dışıyken denge değişimi grafiği aşağıda gösterilmiştir. Bunu görmek için, UseAutoBalanceControl harici parametresi için No değerini ayarlayın.

İlk denge değişimi grafiği

Şekil 4. İlk denge değişimi grafiği


Şimdi UseAutoBalanceControl harici parametresini Yes olarak ayarlayın ve Expert Advisor'ı test edin. Denge eğimini kontrol etmek için etkinleştirilmiş sistemle grafiği alacaksınız.

Kontrol sistemi etkinken denge değişimi grafiği

Şekil 5. Kontrol sistemi etkinken denge değişimi grafiği

Üst grafikte (şek.4) çoğu dönemin kesildiği gibi göründüğünü, alt grafikte (şek.5) ise düz bir forma sahip olduğunu görebilirsiniz. Bu, sistemimizin çalışmasının sonucudur. Expert Advisor'ın çalışmasının ana parametrelerini karşılaştırabilirsiniz:

 Parametre
 UseAutoBalanceControl = Hayır  UseAutoBalanceControl = Evet
 Toplam net kar:  18 378,00 17 261,73
 Kar faktörü:  1,47 1,81
 Kurtarma faktörü:  2,66  3,74
 Beklenen kazanç:  117,81 110,65
 Mutlak bakiye düşüşü: 1 310,50 131,05
 Mutlak hisse senedi düşüşü:  1 390,50 514,85
 Maksimum bakiye düşüşü:  5 569,50 (%5,04) 3 762,15 (%3,35)
 Maksimum hisse senedi düşüşü: 6 899,50 (%6,19)
4 609,60 (%4,08)


Karşılaştırılanlar arasında en iyi olan parametreler yeşil renkle vurgulanır. Kar ve beklenen kazanç biraz azaldı; bu, iş hacmi durumları arasındaki geçiş gecikmelerinin bir sonucu olarak ortaya çıkan düzenlemenin diğer yüzüdür. Sonuç olarak, Expert Advisor'ın çalışma oranlarında bir iyileşme vardır. Özellikle de, düşüş ve kar faktöründe bir iyileşme mevcuttur.


Sonuç

Bu sistemi iyileştirmenin birkaç yolunu görüyorum:
  • Expert Advisor elverişsiz bir çalışma dönemine girdiğinde sanal alım satımı kullanmak. O zaman normal iş hacmi artık önemli olmayacak. Düşüşün azaltılmasına izin verecektir.
  • Expert Advisor'ın mevcut çalışma durumunu belirlemek için daha karmaşık algoritmalar kullanmak (karlı veya karlı olmayan). Örneğin, böyle bir analiz için bir nöron ağı uygulamayı deneyebiliriz. Bu durumda elbette ek incelemeye ihtiyaç vardır.

Böylece, bir Expert Advisor'ın kalite özelliklerinin iyileştirilmesine olanak sağlayan sistemin çalışma prensibini ve sonucunu göz önünde bulundurduk. Para yönetimi sistemi ile ortak çalışma, bazı durumlarda, risk artırılmadan karlılığın artırılmasına olanak tanır.

Size bir kez daha hatırlatıyorum: Hiçbir yardımcı sistem, kaybeden bir sistemden karlı bir Expert Advisor yapamaz.


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

Ekli dosyalar |
Otomatik Alım Satım Şampiyonası 2010 için Bir Expert Advisor Nasıl Hızlı Bir Şekilde Oluşturulur? Otomatik Alım Satım Şampiyonası 2010 için Bir Expert Advisor Nasıl Hızlı Bir Şekilde Oluşturulur?
2010 Otomatik Alım Satım Şampiyonası'na katılacak bir expert geliştirmek için hazır bir expert advisor şablonu kullanalım. Acemi bir MQL5 programcısı dahi bu görevi yerine getirebilir; zira stratejileriniz için temel sınıflar, işlevler, şablonlar zaten geliştirildi. Alım satım fikrinizi uygulamak için minimum miktarda kod yazmanız yeterlidir.
Expert Advisor yazarken MQL5 Standard Alım Satım Sınıfı kitaplıklarının kullanımı Expert Advisor yazarken MQL5 Standard Alım Satım Sınıfı kitaplıklarının kullanımı
Bu makalede, bir alım satım işlemi yapmadan önce pozisyon kapatma ve değiştirme, bekleyen talimat verme ve Marjın silinmesi ve doğrulanmasını uygulayan Expert Advisor'ları yazarken MQL5 Standart Kitaplık Alım Satım Sınıflarının başlıca işlevlerinin nasıl kullanılacağı açıklanmaktadır. Ayrıca, talimat ve yatırım ayrıntılarını elde etmek için Alım Satım sınıflarının nasıl kullanılabileceğini de gösterdik.
Hataları Bulma ve Günlüğe Kaydetme Hataları Bulma ve Günlüğe Kaydetme
MetaEditor 5 hata ayıklama özelliğine sahiptir. Ancak MQL5 programlarınızı yazarken, genellikle ayrı değerleri değil, test ve çevrimiçi çalışma sırasında görünen tüm mesajları görüntülemek istersiniz. Günlük dosyası içeriğinin boyutu büyük olduğunda, gerekli mesajın hızlı ve kolay alınmasını otomatikleştirmek aşikardır. Bu makalede MQL5 programlarında hata bulma yollarını ve günlüğe kaydetme yöntemlerini ele alacağız. Ayrıca, dosyalara günlük tutmayı basitleştireceğiz ve günlüklerin rahat bir şekilde görüntülenmesi için basit LogMon programı hakkında bilgi edineceğiz.
Karı Geri Çekme İşlemlerini Modellemek için TesterWithdrawal() İşlevini Kullanma Karı Geri Çekme İşlemlerini Modellemek için TesterWithdrawal() İşlevini Kullanma
Bu makalede, işlem sırasında varlıkların belirli bir bölümünün geri çekilmesini gerektiren alım satım sistemlerindeki riskleri tahmin etmek için TesterWithDrawal() işlevinin kullanımı açıklanmaktadır. Ayrıca, bu işlevin strateji test cihazında hisse senedi düşüşü hesaplama algoritması üzerindeki etkisi de açıklanmaktadır. Bu işlev, Expert Advisor'larınızın parametresini optimize ederken kullanışlıdır.