English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Alım Satım Sistemlerinin Değerlendirilmesi - Genel Olarak Giriş, Çıkış ve İşlemlerin Etkililiği

Alım Satım Sistemlerinin Değerlendirilmesi - Genel Olarak Giriş, Çıkış ve İşlemlerin Etkililiği

MetaTrader 5Sınayıcı | 9 Aralık 2021, 11:13
172 0
Mykola Demko
Mykola Demko

Giriş

Bir alım satım sisteminin etkililiğini belirleyen pek çok ölçüt vardır ve yatırımcılar beğendiklerini seçerler. Bu makale, S.V. Bulashev'in "Statistika dlya traderov" ("Yatırımcılar için İstatistikler") kitabında açıklanan yaklaşımları anlatmaktadır. Ne yazık ki bu kitabın çok az sayıda nüshası vardır ve uzun süredir yeni baskısı yapılmamıştır, ancak elektronik versiyonu hala birçok web sitesinde mevcuttur.


Önsöz

Kitabın 2003 yılında yayınlandığını hatırlatırım. Ve bu, MQL-II programlama dili ile MetaTrader 3'ün çıktığı zamandı. Platform o zamanlar için oldukça ilericiydi. Böylece, modern MetaTrader 5 istemci terminali ile karşılaştırarak alım satım koşullarındaki değişiklikleri bizzat takip edebiliriz. Unutulmamalıdır ki kitabın yazarı, birçok nesil yatırımcı için bir guru olmuştur (bu alandaki nesillerin hızlı değişimi göz önüne alındığında). Ancak zaman durmuyor; kitapta açıklanan ilkeler hala uygulanabilir olmasına rağmen, yaklaşımlar uyarlanmalıdır.

S.V. Bulashev kitabını her şeyden önce o zaman için geçerli olan alım satım koşullarını temel alarak yazdı. Bu nedenle yazarın tarif ettiği istatistikleri bir dönüşüm olmadan kullanamayız. Daha açık hale getirmek için o zamanların alım satım olanaklarını hatırlayalım: Spot piyasada marjinal alım satım, spekülatif bir kâr elde etmek için bir para biriminin satın alınmasının bir süre sonra onu satmaya dönüşmesi anlamına gelir.

Bunlar temel bilgilerdir ve "Yatırımcılar için İstatistikler" kitabı yazıldığında tam yorumlamanın kullanıldığını hatırlatmakta fayda var. 1 lotluk her sözleşme, aynı hacmin ters yatırımıyla kapatılmış olmalıdır. Ancak iki yıl sonra (2005'te), bu tür istatistiklerin kullanımı için bir yeniden yapılanma gerekmiştir. Bunun nedeni, MetaTrader 4'te sözleşmelerin kısmen kapatılmasının mümkün olmasıdır. Bu nedenle, Bulashev'in tanımladığı istatistikleri kullanmak için yorumlama sistemini geliştirmemiz gerekiyor, özellikle yorumlama, açma ile değil kapatma gerçeğiyle yapılmalıdır.

5 yıl sonra durum önemli ölçüde değişti. Bu kadar alışılmış bir terim olan Emir nerede? Kayboldu. Bu forumdaki soruların akışını göz önünde bulundurarak, MetaTrader 5'te tam yorumlama sistemini açıklamak daha iyidir.

Yani, bugün artık klasik bir Emir terimi yoktur. Artık bir emir, bir alım satım pozisyonunu açmak veya değiştirmek için bir yatırımcı veya MTS tarafından bir aracı sunucusuna yapılan bir alım satım talebidir. Şimdi bu bir pozisyondur; bunun anlamını anlamak için marjinal alım satımdan bahsettim. Gerçek şu ki, marjinal alım satım ödünç alınan para üzerinden yapılır ve o para var olduğu sürece bir pozisyon mevcuttur.

Pozisyonu kapatarak ve bunun sonucunda kârı/zararı sabitleyerek borçlu ile hesapları kapattığınız anda, pozisyonunuz durur. Bu arada bu durum, pozisyonun tersinin neden bunu kapatmadığını açıklıyor. Gerçek şu ki borç yine de kalır ve satın almak veya satmak için borç aldıysanız arada bir fark yoktur. Sözleşme, yalnızca yürütülen bir emrin geçmişidir.

Şimdi alım satım özelliklerinden bahsedelim. Şu anda MetaTrader 5'te bir alım satım pozisyonunu hem kısmen kapatabiliyoruz hem de mevcut olanı artırabiliyoruz. Böylece belli bir hacimdeki bir pozisyonun her açılışının ardından aynı hacimdeki kapanışın takip edildiği klasik yorumlama sistemi geçmişte kalmıştır. Ancak MetaTrader 5'te saklanan bilgilerden onu kurtarmak gerçekten imkansız mıdır? Yani her şeyden önce yorumlamayı yeniden düzenleyeceğiz.


Girişin Etkililiği

Pek çok insanın, alım satımlarını daha etkili hale getirmek istediği bir sır değildir ancak bu terimi nasıl tanımlamalıyız (resmi hale getirmek)? Bir sözleşmenin, fiyatın geçtiği bir yol olduğunu varsayarsanız, o yol üzerinde iki uç nokta olduğu ortaya çıkar: gözlemlenen bölümde minimum ve maksimum fiyat. Herkes (satın alırken) piyasaya mümkün olduğu kadar minimuma yakın girmeye çalışır. Bu, herhangi bir alım satım işleminin ana kuralı olarak kabul edilebilir: düşük fiyata al, yüksek fiyata sat.

Girişin etkililiği, satın alırken minimuma ne kadar yakın olduğunuzu belirler. Başka bir deyişle, girişin etkililiği, maksimum ile giriş fiyatı arasındaki mesafenin tüm yola oranıdır. Neden minimuma olan mesafeyi maksimum farkıyla ölçüyoruz? Etkililiğin minimumda girerken 1'e eşit (ve maksimumda girerken 0'a eşit) olmasına ihtiyacımız var.

Bu yüzden oranımız için minimum ve giriş arasındaki mesafeyi değil, kalan mesafeyi alıyoruz. Burada satışın durumunun satın almaya kıyasla yansıtıldığını belirtmemiz gerekiyor.

 

Pozisyona girmenin etkililiği, bir MTS'nin belirli bir alım satım sırasında giriş fiyatına göre potansiyel kârı ne kadar iyi gerçekleştirdiğini gösterir. Emirlerdeki marj, aşağıdaki formüller ile hesaplanır:

for long positions
enter_efficiency=(max_price_trade-enter_price)/(max_price_trade-min_price_trade);

for short positions
enter_efficiency=(enter_price-min_price_trade)/(max_price_trade-min_price_trade);

The effectiveness of entering can have a value within the range from 0 to 1.


Çıkışın Etkililiği

Çıkıştaki durum da benzerdir:


Bir pozisyondan çıkışın etkililiği, bir MTS'nin belirli bir alım satım sırasında pozisyondan çıkış fiyatına göre potansiyel kârı ne kadar iyi gerçekleştirdiğini gösterir. Emirlerdeki marj, aşağıdaki formüller ile hesaplanır:


for lone positions
exit_efficiency=(exit_price - min_price_trade)/(max_price_trade - min_price_trade);

for short positions
exit_efficiency=(max_price_trade - exit_price)/(max_price_trade - min_price_trade);

The effectiveness of exiting can have a value withing the range from 0 to 1.


Bir Alım Satımın Etkililiği

Genel olarak, bir alım satımın etkililiği hem giriş hem de çıkış ile belirlenir. Alım satım sırasında giriş ve çıkış arasındaki (yani minimum ve maksimum arasındaki fark) yolun, maksimum mesafeye oranı olarak hesaplanabilir. Bu nedenle, bir alım satımın etkililiği iki şekilde hesaplanabilir - doğrudan alım satımla ilgili birincil bilgileri kullanarak veya önceden değerlendirilmiş giriş ve çıkışların (bir aralık kayması ile) zaten hesaplanmış sonuçlarını kullanarak.

Ticaretin etkililiği, bir MTS'nin belirli bir alım satım sırasında toplam potansiyel kârı ne kadar iyi gerçekleştirdiğini gösterir. Aşağıdaki formüllerle hesaplanır:

for long positions
trade_efficiency=(exit_price-enter_price)/(max_price_trade-min_price_trade);

for short positions
trade_efficiency=(enter_price-exit_price)/(max_price_trade-min_price_trade);

general formula
trade_efficiency=enter_efficiency+exit_efficiency-1;

The effectiveness of trade can have a value within the range from -1 to 1.
The effectiveness of trade must be greater than 0,2. 
The analysis of effectiveness visually shows the direction for enhancing the system, because it allows evaluating the quality of signals for entering and exiting a position separately from each other.


Yorumlamanın Dönüşümü

Her şeyden önce, herhangi bir karışıklığa mahal vermemek için yorum nesnelerinin adlarını netleştirmemiz gerekir. Aynı terimler - emir, sözleşme, pozisyon MetaTrader 5'te ve Bulachev tarafından kullanıldığından, bunları birbirinden ayırmamız gerekiyor. Makalemde, Bulachev'in yorum nesnesi için "alım satım" adını kullanacağım, yani alım satım bir sözleşmedir; ayrıca bunun için "emir" terimini kullanır, bu bağlamda bu terimler aynıdır. Bulachev, tamamlanmamış bir sözleşmeyi pozisyon olarak adlandırıyor ve biz buna kapanmamış alım satım diyeceğiz.

Burada her 3 terimin de tek bir "alım satım" kelimesine kolayca uyduğunu görebilirsiniz. MetaTrader 5'teki yorumu yeniden adlandırmayacağız ve bu üç terimin anlamı, istemci terminalinin geliştiricileri tarafından tasarlananla aynı kalıyor. Sonuç olarak kullanacağımız 4 kelime var - Pozisyon, Sözleşme, Emir ve Ticaret.

Bir Emir, sunucuya bir pozisyonu açmak/değiştirmek için verilen bir komut olduğundan doğrudan istatistikleri ilgilendirmez ancak bunu bir sözleşme yoluyla dolaylı olarak yapar (bunun nedeni, bir emri göndermenin, her zaman belirtilen hacim ve fiyattaki karşılık gelen bir sözleşmenin yürütülmesiyle sonuçlanmamasıdır), bu yüzden istatistikleri emirlere göre değil, sözleşmelere göre toplamak doğru olur.

Aynı pozisyonun bir yorumlama örneğini ele alalım (yukarıdaki açıklamayı daha açık hale getirmek için):

interpretation in МТ-5
deal[ 0 ]  in      0.1   sell   1.22218   2010.06.14 13:33
deal[ 1 ]  in/out  0.2   buy    1.22261   2010.06.14 13:36
deal[ 2 ]  in      0.1   buy    1.22337   2010.06.14 13:39
deal[ 3 ]  out     0.2   sell   1.22310   2010.06.14 13:41
interpretation by Bulachev
trade[ 0 ]  in 0.1  sell 1.22218 2010.06.14 13:33   out 1.22261 2010.06.14 13:36
trade[ 1 ]  in 0.1  buy  1.22261 2010.06.14 13:36   out 1.22310 2010.06.14 13:41
trade[ 2 ]  in 0.1  buy  1.22337 2010.06.14 13:39   out 1.22310 2010.06.14 13:41


Şimdi bu manipülasyonların nasıl yapıldığını anlatacağım. Deal[ 0 ] pozisyonu açar, bunu yeni alım satımın başlangıcı olarak yazarız:

trade[ 0 ]  in 0.1  sell 1.22218 2010.06.14 13:33

Ardından pozisyonun tersi gelir; bu, önceki tüm alım satımların kapatılması gerektiği anlamına gelir. Buna bağlı olarak, ters deal[ 1 ] hakkındaki bilgiler hem yeni alım satımın kapanışında hem de açılışında dikkate alınacaktır. Giriş/çıkış yönü ile sözleşmeden önceki tüm kapatılmamış alım satımlar kapatıldıktan sonra, yeni alım satım işlemi açmamız gerekir. Yani, tür ve hacim ek olarak kullanıldığında, bir işlemin açılmasının aksine, kapanış için seçilen sözleşmeyle ilgili yalnızca fiyat ve zaman bilgilerini kullanırız. Burada, yeni yorumlamada ortaya çıkmadan önce kullanılmayan bir terimin de sözleşmenin yönü olduğunu açıklığa kavuşturmamız gerekiyor. Daha önce "yön" derken alım veya satımı kastetmiştik, aynı anlamda "tür" terimi de vardı. Şu andan itibaren tür ve yön farklı terimlerdir.

Tür bir alım veya satımdır, yön ise bir pozisyona girmek veya çıkmaktır. Bu nedenle bir pozisyon her zaman içeri yönlü bir sözleşme ile açılır ve çıkış yönlü bir sözleşme ile kapatılır. Ancak yön sadece pozisyonların açılıp kapanması ile sınırlı değildir. Bu terim aynı zamanda bir pozisyonun hacminin arttırılmasını ("giriş" sözleşmesi listede ilk değilse) ve bir pozisyonun kısmen kapanmasını ("çıkış" sözleşmeleri listede sonuncu değildir) içerir. Kısmi kapatma mevcut olduğundan, pozisyonun tersini de eklemek mantıklıdır; mevcut pozisyondan daha büyük bir boyutta ters bir sözleşme gerçekleştirildiğinde ters işlem gerçekleşir, yani bu bir giriş/çıkış sözleşmesidir.

Böylece, daha önce açılmış olan alım satımları kapattık (pozisyonu tersine çevirmek için):

trade[ 0 ]  in 0.1  sell 1.22218 2010.06.14 13:33   out 1.22261 2010.06.14 13:36

Kalan hacim 0,1 lottur ve yeni alım satımın açılması için kullanılır:

trade[ 1 ]  in 0.1  buy  1.22261 2010.06.14 13:36

Ardından, giriş yönü ile deal[ 2 ] gelir, başka bir alım satım işlemi açın:

trade[ 2 ]  in 0.1  buy  1.22337 2010.06.14 13:39

Son olarak, pozisyonu kapatan sözleşme - deal[ 3 ], pozisyondaki henüz kapanmamış tüm alım satımları kapatır:

trade[ 1 ]  in 0.1  buy  1.22261 2010.06.14 13:36   out 1.22310 2010.06.14 13:41
trade[ 2 ]  in 0.1  buy  1.22337 2010.06.14 13:39   out 1.22310 2010.06.14 13:41

Yukarıda açıklanan yorum, Bulachev tarafından kullanılan yorumun özünü göstermektedir - her açık alım satımın belirli bir giriş noktası ve belirli bir çıkış noktası, kendi hacmi ve türü vardır. Ancak bu yorumlama sistemi tek bir nüansı dikkate almaz - kısmi kapanış. Daha yakından bakarsanız, alım satım sayısının gelen giriş sözleşmesi sayısına eşit olduğunu göreceksiniz (giriş/çıkış sözleşmeleri dikkate alındığında). Bu durumda, giriş sözleşmeleri tarafından yorumlanmaya değerdir, ancak kısmi kapanışta daha fazla çıkış sözleşmesi olacak (giriş ve çıkış sözleşmelerinin sayısının aynı olduğu, ancak hacimsel olarak birbirlerine karşılık gelmediği bir durum olabilir).

Tüm çıkış sözleşmelerini işlemek için çıkış sözleşmelerine göre yorumlamalıyız. İlk başta tüm giriş ve tüm çıkış (veya tam tersi) sözleşmeleri dahil olmak üzere sözleşmeleri ayrı ayrı işlersek bu çelişki çözülmez gibi görünür. Ancak sözleşmeleri sırayla işler ve her birine özel bir işleme kuralı uygularsak, çelişki olmaz.

Burada, çıkış sözleşmelerinin sayısının giriş sözleşmelerinin sayısından fazla olduğu bir örnek verilmiştir (açıklamayla birlikte):

interpretation in МТ-5
deal[ 0 ]  in      0.3   sell      1.22133   2010.06.15 08:00
deal[ 1 ]  out     0.2   buy       1.22145   2010.06.15 08:01
deal[ 2 ]  in/out  0.4   buy       1.22145   2010.06.15 08:02
deal[ 3 ]  in/out  0.4   sell      1.22122   2010.06.15 08:03
deal[ 4 ]  out     0.1   buy       1.2206    2010.06.15 08:06
interpretation by Bulachev                                       
trade[ 0 ]  in 0.2  sell    1.22133 2010.06.15 08:00   out 1.22145 2010.06.15 08:01   
trade[ 1 ]  in 0.1  sell    1.22133 2010.06.15 08:00   out 1.22145 2010.06.15 08:02   
trade[ 2 ]  in 0.3  buy     1.22145 2010.06.15 08:02   out 1.22122 2010.06.15 08:03   
trade[ 3 ]  in 0.1  sell    1.22122 2010.06.15 08:03   out 1.2206  2010.06.15 08:06    

Açılıştan sonra bir kapanış sözleşmesinin geldiği ancak bunun tüm hacme değil sadece bir kısmına sahip olduğu bir durum söz konusudur (0,3 lot açıldı ve 0,2 kapandı). Böyle bir durum nasıl yönetilir? Her alım satım aynı hacimde kapatılırsa durum, birkaç alım satımın tek bir sözleşmeyle açılması olarak düşünülebilir. Böylece, aynı açılış noktalarına ve farklı kapanış noktalarına sahip olacaklar (her bir işlemin hacminin, kapanış hacmi tarafından belirleneceği açıktır). Örneğin, işleme için deal[ 0 ] seçiyoruz, alım satımı açıyoruz:

trade[ 0 ]  in 0.3  sell 1.22133 2010.06.15 08:00

Ardından deal[ 1 ] seçimini yapıyoruz, açık işlemi kapatıyoruz ve kapanış sırasında kapanış hacminin yeterli olmadığını görüyoruz. Önceden açılmış alım satımın bir kopyasını alın ve "hacim" parametresinde hacim eksikliğini belirtin. Bundan sonra ilk alım satımı sözleşme hacmiyle kapatın (yani açılışta belirtilen ilk alım satım hacmini kapanış hacmiyle değiştiririz):

trade[ 0 ]  in 0.2  sell 1.22133 2010.06.15 08:00   out 1.22145 2010.06.15 08:01   
trade[ 1 ]  in 0.1  sell 1.22133 2010.06.15 08:00

Bu tür bir dönüşüm bir yatırımcı için uygun görünmeyebilir, çünkü yatırımcı bunu değil başka bir yatırımcıyı kapatmak isteyebilir. Ancak yine de doğru bir dönüşüm sonucunda sistemlerin değerlendirilmesi zarar görmeyecektir. Zarar görebilecek tek şey, yatırımcının MetaTrader 4'te zararsız alım satım işlemlerine olan güvenidir; bu yeniden hesaplama sistemi tüm yanılgıları ortaya çıkaracaktır.

Bulachev'in kitabında açıklanan istatistiksel yorumlama sisteminde duygular yoktur ve kararları giriş, çıkış pozisyonları ve toplamda her iki orandan dürüstçe değerlendirmeye izin verir. Yorumlamanın (veri kaybı olmadan birinden diğerine) dönüştürülmesi olasılığı, MetaTrader 4 için geliştirilen bir MTS'nin MetaTrader 5'in yorumlama sistemi için yeniden yapılamayacağını söylemenin yanlış olduğunu kanıtlıyor. Yorumu dönüştürürken tek kayıp, hacmin farklı emirlere ait olması olabilir (MetaTrader 4). Aslında hesaba katılması gereken (bu terimin eski anlamına göre) daha fazla emir yoksa bu sadece bir yatırımcının öznel tahminidir.


Yorumlama Dönüşümü Kodu

Kodun kendisine bir göz atalım. Bir çevirmen hazırlamak için OOP'nin kalıtım özelliğine ihtiyacımız var. Bu yüzden henüz aşina olmayanlara MQL5 Kullanım Kılavuzunu açmalarını ve teori öğrenmelerini öneriyorum. Her şeyden önce, bir sözleşmenin yorumlama yapısını tanımlayalım (bu değerleri doğrudan MQL5'in standart fonksiyonlarını kullanarak alıp kodu hızlandırabiliriz ancak bu daha az okunabilirdir ve sizi şaşırtabilir).

//+------------------------------------------------------------------+
//| structure of deal                                                |
//+------------------------------------------------------------------+
struct S_Stat_Deals
  {
public:
   ulong             DTicket;         // ticket of deal   
   ENUM_DEAL_TYPE     deals_type;      // type of deal
   ENUM_DEAL_ENTRY    deals_entry;     // direction of deal 
   double            deals_volume;    // volume of deal    
   double            deals_price;     // price of opening of deal   
   datetime          deals_date;      // time of opening of deal  

                     S_Stat_Deals(){};
                    ~S_Stat_Deals(){};
  };

Bu yapı, bir sözleşme ile ilgili tüm ana detayları içerir, gerektiğinde hesaplayabileceğimiz için türev ayrıntılar dahil edilmez. Geliştiriciler strateji test cihazında Bulachev'in istatistiklerinin birçok yöntemini zaten uygulamış olduklarından bizim yalnızca özel yöntemlerle bunu tamamlamamız kaldı. O halde, bir bütün olarak ticaretin etkililiği, açılış ve kapanışın etkililiği gibi yöntemleri uygulayalım.

Bu değerleri elde etmek için bir alım satım sırasında açılış/kapanış fiyatı, açılış/kapanış zamanı, minimum/maksimum fiyat gibi birincil bilgilerin yorumlanmasını uygulamamız gerekir. Bu tür birincil bilgilere sahipsek, birçok türev bilgi elde edebiliriz. Ayrıca aşağıda açıklanan alım satım yapısına da dikkatinizi çekmek istiyorum, bu ana yapıdır, tüm yorum dönüşümleri ona dayanmaktadır.

//+------------------------------------------------------------------+
//| structure of trade                                               |
//+------------------------------------------------------------------+
struct S_Stat_Trades
  {
public:
   ulong             OTicket;         // ticket of opening deal
   ulong             CTicket;         // ticket of closing deal     
   ENUM_DEAL_TYPE     trade_type;     // type of trade
   double            trade_volume;    // volume of trade
   double            max_price_trade; // maximum price of trade
   double            min_price_trade; // minimum price of trade
   double            enter_price;     // price of opening of trade
   datetime          enter_date;      // time of opening of trade
   double            exit_price;      // price of closing of trade/s22>
   datetime          exit_date;       // time of closing of trade

   double            enter_efficiency;// effectiveness of entering
   double            exit_efficiency; // effectiveness of exiting
   double            trade_efficiency;// effectiveness of trade

                     S_Stat_Trades(){};
                    ~S_Stat_Trades(){};
  };


Şimdi, iki ana yapı oluşturduğumuz için yorumlamayı dönüştüren yeni C_Pos sınıfını tanımlayabiliriz. Her şeyden önce sözleşmelerin ve alım satımların yorumlama yapılarının işaretçilerini belirtelim. Bilgi, devralınan fonksiyonlarda gerekli olabileceğinden, onu genel olarak bildirin ve çok sayıda sözleşme ve alım satım olabileceğinden, bir değişken yerine yapıya işaretçi olarak bir dizi kullanın. Böylece bilgi yapılandırılmış ve herhangi bir yerden erişilebilir olacaktır.

Daha sonra geçmişi ayrı pozisyonlara ayırmamız ve tüm dönüşümleri tam bir alım satım döngüsünde olduğu gibi bir pozisyon içinde gerçekleştirmemiz gerekiyor. Bunu yapmak için pozisyonun niteliklerinin yorumlanması için değişkenleri bildirin (pozisyon kimliği, pozisyon sembolleri, sözleşme sayısı, alım satım sayısı).

//+------------------------------------------------------------------+
//| class for transforming deals into trades                         |
//+------------------------------------------------------------------+
class C_Pos
  {
public:
   S_Stat_Deals      m_deals_stats[];  // structure of deals
   S_Stat_Trades     m_trades_stats[]; // structure of trades
   long              pos_id;          // id of position
   string            symbol;          // symbol of position
   int               count_deals;     // number of deals
   int               count_trades;    // number of trades
   int               trades_ends;     // number of closed trades
   int               DIGITS;          // accuracy of minimum volume by the symbols of position  
                     C_Pos()
     {
      count_deals=0;
      count_trades=0;
      trades_ends=0;
     };
                    ~C_Pos(){};
   void              OnHistory();         // creation of history of position
   void              OnHistoryTransform();// transformation of position history into the new system of interpretation
   void              efficiency();        // calculation of effectiveness by Bulachev's method

private:
   void              open_pos(int c);
   void              copy_pos(int x);
   void              close_pos(int i,int c);
   double            nd(double v){return(NormalizeDouble(v,DIGITS));};// normalization to minimum volume
   void              DigitMinLots(); // accuracy of minimum volume
   double            iHighest(string          symbol_name,// symbol name
                              ENUM_TIMEFRAMES  timeframe,  // period
                              datetime         start_time, // start date
                              datetime         stop_time   // end date
                              );
   double            iLowest(string          symbol_name,// symbol name
                             ENUM_TIMEFRAMES  timeframe,  // period
                             datetime         start_time, // start date
                             datetime         stop_time   // end date
                             );
  };


Sınıfın, pozisyonları işleyen üç genel yöntemi vardır.

OnHistory() pozisyon geçmişini oluşturur:
//+------------------------------------------------------------------+
//| filling the structures of history deals                          |
//+------------------------------------------------------------------+
void C_Pos::OnHistory()
  {
   ArrayResize(m_deals_stats,count_deals);
   for(int i=0;i<count_deals;i++)
     {
      m_deals_stats[i].DTicket=HistoryDealGetTicket(i);
      m_deals_stats[i].deals_type=(ENUM_DEAL_TYPE)HistoryDealGetInteger(m_deals_stats[i].DTicket,DEAL_TYPE);   // type of deal
      m_deals_stats[i].deals_entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(m_deals_stats[i].DTicket,DEAL_ENTRY);// direction of deal
      m_deals_stats[i].deals_volume=HistoryDealGetDouble(m_deals_stats[i].DTicket,DEAL_VOLUME);              // volume of deal
      m_deals_stats[i].deals_price=HistoryDealGetDouble(m_deals_stats[i].DTicket,DEAL_PRICE);                // price of opening
      m_deals_stats[i].deals_date=(datetime)HistoryDealGetInteger(m_deals_stats[i].DTicket,DEAL_TIME);        // time of opening
     }
  };

Yöntem, her sözleşme için yapının bir kopyasını oluşturur ve onu sözleşme hakkındaki bilgilerle doldurur. Yukarıda onsuz da yapabiliriz derken tam olarak bunu kastetmiştim ama onunla daha uygun (mikrosaniyelik zamanın kısalmasının peşine düşenler bu yapıların çağrısını, eşitlik işaretinin sağındaki çizgiyle değiştirebilirler).

OnHistoryTransform(), pozisyon geçmişini yeni yorumlama sistemine dönüştürür:

  • Bilginin nasıl dönüştürülmesi gerektiğini daha önce anlatmıştım, şimdi buna bir örnek verelim. Dönüşüm için bir sözleşmenin hacmini (min. hacim) hesaplamamız gereken doğrulukta bir değere ihtiyacımız var; DigitMinLots() bunu halleder ancak bir programcı bu kodun başka hiçbir koşulda yürütülmeyeceğinden eminse bu parametre yapıcıda belirtilebilir ve fonksiyon atlanabilir.
  • Ardından count_trades ve trades_ends sayaçlarını sıfırlayın. Bundan sonra, fonksiyonların yorumlanmasının yapısı için belleği yeniden tahsis edin. Fonksiyonların tam sayısını kesin olarak bilmediğimiz için pozisyondaki sözleşme sayısına göre belleği yeniden tahsis etmeliyiz. Daha fazla alım satım olduğu ortaya çıkarsa belleği tekrar birkaç kez yeniden tahsis edeceğiz; ancak aynı zamanda çoğu alım satımın yeterli belleği olacaktır ve tüm dizi için bellek tahsisi makine zamanımızı önemli ölçüde azaltır.

Gerektiğinde her yerde bu yöntemi kullanmanızı tavsiye ederim; yeni bir yorumlama nesnesi göründüğünde belleği tahsis edin. Gerekli bellek miktarı hakkında kesin bir bilgi yoksa bunu yaklaşık bir değere tahsis etmemiz gerekir. Her durumda, tüm diziyi her adımda yeniden tahsis etmekten daha ekonomiktir.

Ardından, bir pozisyonun tüm sözleşmelerinin üç filtre kullanılarak filtrelendiği döngü gelir: sözleşme giriş, giriş/çıkış, çıkış ise. Her değişken için özel eylemler uygulanır. Filtreler sıralıdır, iç içedir. Başka bir deyişle, bir filtre false öğesini döndürürse yalnızca bu durumda bir sonraki filtreyi kontrol ederiz. Bu tür yapı, kaynaklarla ekonomiktir çünkü gereksiz eylemler kesilir. Kodu daha okunabilir hale getirmek için sınıfta özel olarak bildirilen fonksiyonlara birçok işlem yapılır. Bu arada, bu fonksiyonlar geliştirme sırasında geneldi ancak daha sonra kodun diğer bölümlerinde bunlara ihtiyaç olmadığını fark ettim, bu nedenle özel fonksiyonlar olarak yeniden bildirildiler. OOP'deki verilerin kapsamını değiştirmek bu kadar kolay.

Böylece, giriş filtresinde yeni bir alım satımın oluşturulması gerçekleştirilir (open_pos() fonksiyonu), bu nedenle işaretçi dizisinin boyutunu bir adım artırırız ve sözleşme yapısını alım satım yapısının ilgili alanlarına kopyalarız. Ayrıca alım satımın yapısı iki kat daha fazla fiyat ve zaman alanına sahip olduğundan, bir işlem açıldığında sadece açılış alanları doldurulur, dolayısıyla tamamlanmamış sayılır; bunu count_trades ve trades_ends farkıyla anlayabilirsiniz. Mesele şu ki, başlangıçta sayaçlar sıfır değerine sahiptir. Bir alım satım göründüğü anda, count_trades sayacı artar ve alım satım işlemi kapatıldığında, trades_ends sayacı artar. Böylece, count_trades ve trades_ends arasındaki fark, herhangi bir zamanda kaç alım satımın kapalı olmadığını size söyleyebilir.

open_pos() fonksiyonu oldukça basittir, yalnızca alım satımları açar ve karşılık gelen sayacı tetikler; diğer benzeri fonksiyonlar o kadar basit değildir. Bu nedenle, bir sözleşme giriş türünde değilse o zaman giriş/çıkış veya çıkış olabilir. Her şeyden önce, iki değişkenden daha kolay yürütüleni kontrol edin (bu temel bir sorun değildir, ancak kontrolü, artan yürütme zorluğu sırasına göre oluşturdum).

Giriş/çıkış filtresini işleyen fonksiyon, tüm kapatılmamış alım satımların açık pozisyonlarını toplar (count_trades ve trades_ends arasındaki farkı kullanarak hangi alım satımların kapalı olmadığını nasıl bileceğimi daha önce belirtmiştim). Böylece, belirli bir sözleşme tarafından kapatılan toplam hacmi hesaplarız (ve hacmin geri kalanı mevcut sözleşmenin türü ile yeniden açılacaktır). Burada, sözleşmenin giriş/çıkış yönüne sahip olduğunu, bunun hacminin daha önce açılmış pozisyonun toplam hacmini aştığını belirtmemiz gerekiyor. Bu nedenle, yeniden açılacak yeni alım satımın hacmini bilmek için pozisyon ile giriş/çıkış sözleşmesi arasındaki farkı hesaplamak mantıklıdır.

Bir sözleşmenin çıkış yönü varsa o zaman her şey daha da karmaşıktır. Her şeyden önce, bir pozisyondaki son sözleşme her zaman çıkış yönüne sahiptir, bu yüzden burada bir istisna yapmalıyız - eğer bu son sözleşmeyse, elimizdeki her şeyi kapatın. Aksi takdirde (sözleşme, sonuncu olan değilse), iki varyant mümkündür. Sözleşme giriş/çıkış değil, çıkış olduğundan dolayı varyantlar şunlardır: ilk varyant, açılışta olan hacmin aynısıdır, yani açılış sözleşmesinin hacmi, kapanış sözleşmesinin hacmine eşittir; ikinci varyant, hacimleri aynı olmayanlardır.

İlk varyant kapatılarak işlenir. İkinci varyant daha karmaşıktır, yine iki varyant mümkündür: hacim daha büyük olduğunda ve hacim açılış hacminden daha az olduğunda. Hacim daha büyük olduğunda, kapanış hacmi açılış hacmine eşit veya bundan daha az olana kadar bir sonraki alım satımı kapatın. Hacim bir sonraki alım satımın tamamını kapatmak için yeterli değilse (daha az hacim vardır) bu, kısmi kapanış anlamına gelir. Burada ticareti yeni hacimle (önceki işlemlerden sonra kalan) kapatmamız gerekiyor ancak ondan önce eksik hacimli alım satımın bir kopyasını almamız gerekiyor. Elbette, sayaçları da unutmayın.

Alım satımda, bir alım satımın yeniden açılmasından sonra kısmi kapanışta zaten bir sonraki alım satım kuyruğunun olduğu bir durum olabilir. Karışıklığı önlemek amacıyla kapanış kronolojisini korumak için hepsi birer birer kaydırılmalıdır.

//+------------------------------------------------------------------+
//| transformation of deals into trades (engine classes)             |
//+------------------------------------------------------------------+
void C_Pos::OnHistoryTransform()
  {
   DigitMinLots();// fill the DIGITS value
   count_trades=0;trades_ends=0;
   ArrayResize(m_trades_stats,count_trades,count_deals);
   for(int c=0;c<count_deals;c++)
     {
      if(m_deals_stats[c].deals_entry==DEAL_ENTRY_IN)
        {
         open_pos(c);
        }
      else// else in
        {
         double POS=0;
         for(int i=trades_ends;i<count_trades;i++)POS+=m_trades_stats[i].trade_volume;

         if(m_deals_stats[c].deals_entry==DEAL_ENTRY_INOUT)
           {
            for(int i=trades_ends;i<count_trades;i++)close_pos(i,c);
            trades_ends=count_trades;
            open_pos(c);
            m_trades_stats[count_trades-1].trade_volume=m_deals_stats[c].deals_volume-POS;
           }
         else// else in/out
           {
            if(m_deals_stats[c].deals_entry==DEAL_ENTRY_OUT)
              {
               if(c==count_deals-1)// if it's the last deal
                 {
                  for(int i=trades_ends;i<count_trades;i++)close_pos(i,c);
                  trades_ends=count_trades-1;
                 }
               else// if it's not the last deal
                 {
                  double out_vol=nd(m_deals_stats[c].deals_volume);
                  while(nd(out_vol)>0)
                    {
                     if(nd(out_vol)>=nd(m_trades_stats[trades_ends].trade_volume))
                       {
                        close_pos(trades_ends,c);
                        out_vol-=nd(m_trades_stats[trades_ends].trade_volume);
                        trades_ends++;
                       }
                     else// if the remainder of closed position is less than the next trade
                       {
                        // move all trades forward by one
                        count_trades++;
                        ArrayResize(m_trades_stats,count_trades);
                        for(int x=count_trades-1;x>trades_ends;x--)copy_pos(x);
                        // open a copy with the volume equal to difference of the current position and the remainder
                        m_trades_stats[trades_ends+1].trade_volume=nd(m_trades_stats[trades_ends].trade_volume-out_vol);
                        // close the current trade with new volume, which is equal to remainder
                        close_pos(trades_ends,c);
                        m_trades_stats[trades_ends].trade_volume=nd(out_vol);
                        out_vol=0;
                        trades_ends++;
                       }
                    }// while(out_vol>0)
                 }// if it's not the last deal
              }// if out
           }// else in/out
        }// else in
     }
  };


Etkililiğin Hesaplanması

Yorumlama sistemi bir kez dönüştürüldüğünde, alım satımın etkililiğini Bulachev'in metodolojisine göre değerlendirebiliriz. Bu tür bir değerlendirme için gerekli olan fonksiyonlar efficiency() yönteminde olup, alım satım yapısının hesaplanan verilerle doldurulması da burada gerçekleştirilir. Giriş ve çıkış etkililiği 0'dan 1'e ve tüm alım satım için -1'den 1'e ölçülür.

//+------------------------------------------------------------------+
//| calculation of effectiveness                                     |
//+------------------------------------------------------------------+
void C_Pos::efficiency()
  {
   for(int i=0;i<count_trades;i++)
     {
      m_trades_stats[i].max_price_trade=iHighest(symbol,PERIOD_M1,m_trades_stats[i].enter_date,m_trades_stats[i].exit_date); // maximal price of trade
      m_trades_stats[i].min_price_trade=iLowest(symbol,PERIOD_M1,m_trades_stats[i].enter_date,m_trades_stats[i].exit_date);  // minimal price of trade
      double minimax=0;
      minimax=m_trades_stats[i].max_price_trade-m_trades_stats[i].min_price_trade;// difference between maximum and minimum
      if(minimax!=0)minimax=1.0/minimax;
      if(m_trades_stats[i].trade_type==DEAL_TYPE_BUY)
        {
         //Effectiveness of entering a position
         m_trades_stats[i].enter_efficiency=(m_trades_stats[i].max_price_trade-m_trades_stats[i].enter_price)*minimax;
         //Effectiveness of exiting from a position
         m_trades_stats[i].exit_efficiency=(m_trades_stats[i].exit_price-m_trades_stats[i].min_price_trade)*minimax;
         //Effectiveness of trade
         m_trades_stats[i].trade_efficiency=(m_trades_stats[i].exit_price-m_trades_stats[i].enter_price)*minimax;
        }
      else
        {
         if(m_trades_stats[i].trade_type==DEAL_TYPE_SELL)
           {
            //Effectiveness of entering a position
            m_trades_stats[i].enter_efficiency=(m_trades_stats[i].enter_price-m_trades_stats[i].min_price_trade)*minimax;
            //Effectiveness of exiting from a position
            m_trades_stats[i].exit_efficiency=(m_trades_stats[i].max_price_trade-m_trades_stats[i].exit_price)*minimax;
            //Effectiveness of trade
            m_trades_stats[i].trade_efficiency=(m_trades_stats[i].enter_price-m_trades_stats[i].exit_price)*minimax;
           }
        }
     }
  }


Yöntem, iHighest() ve iLowest() olmak üzere iki özel yöntem kullanır, bunlar benzerdir ve tek fark, istenen veriler ve fmin veya fmax arama fonksiyonudur.

//+------------------------------------------------------------------+
//| searching maximum within the period start_time --> stop_time     |
//+------------------------------------------------------------------+
double C_Pos::iHighest(string           symbol_name,// symbols name
                       ENUM_TIMEFRAMES  timeframe,  // period
                       datetime         start_time, // start date
                       datetime         stop_time   // end date
                       )
  {
   double  buf[];
   datetime  start_t=(start_time/60)*60;// normalization of time of opening
   datetime  stop_t=(stop_time/60+1)*60;// normaliztion of time of closing  
   int period=CopyHigh(symbol_name,timeframe,start_t,stop_t,buf);
   double res=buf[0];
   for(int i=1;i<period;i++)
      res=fmax(res,buf[i]);
   return(res);
  }

Yöntem, belirtilen iki tarih arasındaki dönem içinde maksimumu arar. Tarihler, fonksiyona start_time ve stop_time parametreleri olarak iletilir. Alım satımların tarihleri fonksiyona geçtiğinden ve 1 dakikalık çubuğun ortasında bile bir alım satım talebi gelebileceğinden tarihin, çubuğun en yakın değerine göre normalleştirilmesi fonksiyon içerisinde gerçekleştirilir. Aynısı iLowest() fonksiyonunda da yapılır. Geliştirilen efficiency() yöntemi ile bir pozisyonla çalışmak için gereken tüm işlevselliğe sahibiz; ancak pozisyonun kendisi henüz düzeltilmemiştir. Bunu, önceki tüm yöntemlerin mevcut olacağı yeni bir sınıf belirleyerek geçelim; başka bir deyişle, onu bir C_Pos türevi olarak bildirelim.


Türev Sınıfı (motor sınıfları)

class C_PosStat:public C_Pos

İstatistiksel bilgileri dikkate almak için yeni sınıfa verilecek bir yapı oluşturun.

//+------------------------------------------------------------------+
//| structure of effectiveness                                       |
//+------------------------------------------------------------------+
struct S_efficiency

  {
   double            enter_efficiency; // effectiveness of entering
   double            exit_efficiency;  // effectiveness of exiting
   double            trade_efficiency; // effectiveness of trade
                     S_efficiency()
     {
      enter_efficiency=0;
      exit_efficiency=0;
      trade_efficiency=0;
     };
                    ~S_efficiency(){};
  };


Ayrıca sınıfın kendisini de:

//+------------------------------------------------------------------+
//| class of statistics of trade in whole                            |
//+------------------------------------------------------------------+
class C_PosStat:public C_Pos
  {
public:
   int               PosTotal;         // number of positions in history
   C_Pos             pos[];            // array of pointers to positions
   int               All_count_trades; // total number of trades in history
   S_efficiency      trade[];          // array of pointers to the structure of effectiveness of entering, exiting and trades
   S_efficiency      avg;              // pointer to the structure of average value of effectiveness of entering, exiting and trades
   S_efficiency      stdev;            // pointer to the structure of standard deviation from
                                       // average value of effectiveness of entering, exiting and trades

                     C_PosStat(){PosTotal=0;};
                    ~C_PosStat(){};
   void              OnPosStat();                         // engine classes
   void              OnTradesStat();                      // gathering information about trades into the common array
   
   // functions of writing information to a file
   void              WriteFileDeals(string folder="deals");
   void              WriteFileTrades(string folder="trades");
   void              WriteFileTrades_all(string folder="trades_all");
   void              WriteFileDealsHTML(string folder="deals");
   void              WriteFileDealsHTML2(string folder="deals");
   void              WriteFileTradesHTML(string folder="trades");
   void              WriteFileTradesHTML2(string folder="trades");
   string            enum_translit(ENUM_DEAL_ENTRY x,bool latin=true);// transformation of enumeration into string
   string            enum_translit(ENUM_DEAL_TYPE x,bool latin=true); 
                                                              // transformation of enumeration into string (overloaded)
private:   

   S_efficiency      AVG(int count);                                        // arithmetical mean
   S_efficiency      STDEV(const S_efficiency &mo,int count);               // standard deviation
   S_efficiency      add(const S_efficiency &a,const S_efficiency &b);      //add
   S_efficiency      take(const S_efficiency &a,const S_efficiency &b);     //subtract
   S_efficiency      multiply(const S_efficiency &a,const S_efficiency &b); //multiply
   S_efficiency      divided(const S_efficiency &a,double b);               //divide
   S_efficiency      square_root(const S_efficiency &a);                    //square root
   string            Head_style(string title);
  };  


Bu sınıfı, sondan başa doğru ters yönde incelemenizi öneririm. Her şey dosyalara bir sözleşme ve alım satım tablosu yazmakla biter. Bunun için bir dizi fonksiyon yazılmıştır (her birinin amacını adından anlayabilirsiniz). Fonksiyonlar, iki tür html raporunun yanı sıra sözleşmeler ve alım satımlar hakkında bir csv raporu oluşturur (yalnızca görsel olarak farklılık gösterirler ancak aynı içeriğe sahiptirler).

      void              WriteFileDeals();      // writing csv report on deals
      void              WriteFileTrades();     // writing csv report on trade
      void              WriteFileTrades_all(); // writing summary csv report of fitness functions
      void              WriteFileDealsHTML2(); // writing html report on deals, 1 variant
      void              WriteFileTradesHTML2();// writing html report on trades, 2 variant

enum_translit() fonksiyonu, numaralandırma değerlerini günlük dosyasına yazmak için dizgi türüne dönüştürmek için tasarlanmıştır. Özel bölüm, S_efficiency yapısının çeşitli fonksiyonlarını içerir. Tüm fonksiyonlar, özellikle yapılarla aritmetik işlemler olmak üzere dilin dezavantajlarını oluşturur. Bu yöntemlerin uygulanmasına ilişkin görüşler farklılık gösterdiğinden farklı şekillerde gerçekleştirilebilmektedir. Bunları yapıların alanlarıyla aritmetik işlem yöntemleri olarak gerçekleştirdim. Birisi, her yapı alanını ayrı bir yöntem kullanarak işlemenin daha iyi olduğunu söyleyebilir. Özetle, programcıların sayısı kadar çok sayıda görüş olduğunu söyleyebilirim. Umarım gelecekte bu tür işlemleri yerleşik yöntemler kullanarak gerçekleştirme olanağımız olur.

AVG() yöntemi, iletilen dizinin aritmetik ortalama değerini hesaplar ancak dağılımın tam resmini göstermez, bu nedenle STDEV() standart sapmasını hesaplayan başka bir yöntemle sağlanır. OnTradesStat() fonksiyonu, etkililik değerlerini (önceden OnPosStat() içinde hesaplanmıştır) alır ve bunları istatistiksel yöntemlerle işler. Son olarak, sınıfın ana fonksiyonuna bakalım - OnPosStat().

Bu fonksiyon ayrıntılı olarak ele alınmalıdır. İki bölümden oluşur, bu nedenle kolayca bölünebilir. İlk kısım tüm pozisyonları arar ve id_pos geçici dizisine kaydederek kimliklerini işler. Adım adım: mevcut tüm geçmişi seçin, sözleşmelerin sayısını hesaplayın, sözleşmeleri işleme döngüsünü çalıştırın. Döngü: Sözleşme türü bakiye ise atlayın (başlangıç sözleşmesini yorumlamaya gerek yoktur), aksi takdirde pozisyonun kimliğini değişkene kaydedin ve aramayı gerçekleştirin. Aynı kimlik temelde (id_pos dizisi) zaten mevcutsa sonraki sözleşmeye gidin, aksi takdirde temele kimliği yazın. Bu şekilde, tüm sözleşmeleri işledikten sonra mevcut tüm pozisyon kimlikleri ve pozisyon sayısı ile dolu bir diziye sahibiz.

   long  id_pos[];// auxiliary array for creating the history of positions
   if(HistorySelect(0,TimeCurrent()))
     {
      int HTD=HistoryDealsTotal();
      ArrayResize(id_pos,PosTotal,HTD);
      for(int i=0;i<HTD;i++)
        {
         ulong DTicket=(ulong)HistoryDealGetTicket(i);
         if((ENUM_DEAL_TYPE)HistoryDealGetInteger(DTicket,DEAL_TYPE)==DEAL_TYPE_BALANCE)
            continue;// if it's a balance deal, skip it
         long id=HistoryDealGetInteger(DTicket,DEAL_POSITION_ID);
         bool present=false; // initial state, there's no such position           
         for(int j=0;j<PosTotal;j++)
           { if(id==id_pos[j]){ present=true; break; } }// if such position already exists break

         if(!present)// write id as a new position appears
           {
            PosTotal++;
            ArrayResize(id_pos,PosTotal);
            id_pos[PosTotal-1]=id;
           }
        }
     }
   ArrayResize(pos,PosTotal);

İkinci bölümde, daha önce C_Pos temel sınıfında açıklanan tüm yöntemleri gerçekleştiriyoruz. Pozisyonları aşan ve pozisyonları işlemek için karşılık gelen yöntemleri çalıştıran bir döngüden oluşur. Yöntemin açıklaması aşağıdaki kodda verilmiştir.

   for(int p=0;p<PosTotal;p++)
     {
      if(HistorySelectByPosition(id_pos[p]))// select position
        {
         pos[p].pos_id=id_pos[p]; // assigned id of position to the corresponding field of the class C_Pos
         pos[p].count_deals=HistoryDealsTotal();// assign the number of deal in position to the field of the class C_Pos
         pos[p].symbol=HistoryDealGetString(HistoryDealGetTicket(0),DEAL_SYMBOL);// the same actions with symbol
         pos[p].OnHistory();          // start filling the structure sd with the history of position
         pos[p].OnHistoryTransform(); // transformation of interpretation, filling the structure st.
         pos[p].efficiency();         // calculation of the effectiveness of obtained data
         All_count_trades+=pos[p].count_trades;// save the number of trades for displaying the total number
        }
     }


Sınıfın Çağırma Yöntemleri

Böylece tüm sınıfı düşündük. Geriye bir çağrı örneği vermek kaldı. Oluşturma olanaklarını korumak için çağrıyı bir fonksiyonda açıkça bildirmedim. Ek olarak, sınıfı ihtiyaçlarınız için geliştirebilir, verilerin istatistiksel olarak işlenmesi için yeni yöntemler uygulayabilirsiniz. Bir komut dosyasından sınıfın yöntemini çağırmanın bir örneği şu şekildedir:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
#include <Bulaschev_Statistic.mqh> void OnStart()
  {
   C_PosStat  start;
   start.OnPosStat();
   start.OnTradesStat();
   start.WriteFileDeals();
   start.WriteFileTrades();
   start.WriteFileTrades_all();
   start.WriteFileDealsHTML2();
   start.WriteFileTradesHTML2();
   Print("cko tr ef=" ,start.stdev.trade_efficiency);
   Print("mo  tr ef=" ,start.avg.trade_efficiency);
   Print("cko out ef=",start.stdev.exit_efficiency);
   Print("mo  out ef=",start.avg.exit_efficiency);
   Print("cko in ef=" ,start.stdev.enter_efficiency);
   Print("mo  in ef=" ,start.avg.enter_efficiency);
  }

Komut dosyası, Dosyalar\OnHistory dizinindeki dosyaya veri yazan fonksiyonların miktarına göre 5 rapor dosyası oluşturur. Aşağıdaki ana fonksiyonlar burada bulunur - OnPosStat() ve OnTradesStat(), bunlar gerekli tüm yöntemleri çağırmak için kullanılır. Komut dosyası, bir bütün olarak ticaretin etkililiğinin elde edilen değerini yazdırarak sona erer. Bu değerlerin her biri genetik optimizasyon için kullanılabilir.

Optimizasyon sırasında her raporu bir dosyaya yazmaya gerek olmadığı için Uzman Danışmanda sınıfın çağrısı biraz farklı görünüyor. İlk olarak, bir komut dosyasının aksine, test cihazında bir Uzman Danışman çalıştırılabilir (bunun için hazırlıyoruz). Strateji test cihazında çalışmanın kendine has özellikleri vardır. Optimizasyon yaparken, OnTester() fonksiyonuna erişimimiz vardır, bu durumda onun çalıştırılması OnDeinit() fonksiyonunun çalıştırılmasından önce gerçekleştirilir. Böylece ana dönüşüm yöntemlerinin çağrısı ayrılabilir. Bir Uzman Danışmanın parametrelerinden uygunluk fonksiyonunun modifikasyonunun rahat yapılması için sınıfın bir parçası olarak değil, global bir numaralandırma bildirdim. Bu durumda numaralandırma, C_PosStat sınıfının yöntemleriyle aynı sayfadadır.

//+------------------------------------------------------------------+
//| enumeration of fitness functions                                 |
//+------------------------------------------------------------------+
enum Enum_Efficiency
  {
   avg_enter_eff,
   stdev_enter_eff,
   avg_exit_eff,
   stdev_exit_eff,
   avg_trade_eff,
   stdev_trade_eff
  };

 Uzman Danışman başlığına eklenmesi gereken budur.

#include <Bulaschev_Statistic.mqh>
input Enum_Efficiency result=0;// Fitness function


Şimdi sadece gerekli parametrenin geçişini switch operatörünü kullanarak anlatabiliriz.

//+------------------------------------------------------------------+
//| Expert optimization function                                     |
//+------------------------------------------------------------------+
double OnTester()
  {
   start.OnPosStat();
   start.OnTradesStat();
   double res;
   switch(result)
     {
      case 0: res=start.avg.enter_efficiency;    break;
      case 1: res=-start.stdev.enter_efficiency; break;
      case 2: res=start.avg.exit_efficiency;     break;
      case 3: res=-start.stdev.exit_efficiency;  break;
      case 4: res=start.avg.trade_efficiency;    break;
      case 5: res=-start.stdev.trade_efficiency; break;
      default : res=0; break;
     }  
   return(res);
  }

OnTester() fonksiyonunun,özel fonksiyonun maksimizasyonu için kullanıldığına dikkatinizi çekmek istiyorum. Özel fonksiyonun minimumunu bulmanız gerekiyorsa fonksiyonun kendisini -1 ile çarparak tersine çevirmek daha iyidir. Standart sapma örneğinde olduğu gibi herkes stdev ne kadar küçükse alım satımların etkililiği arasındaki farkın o kadar küçük olduğunu anlar, bu nedenle alım satımların istikrarı daha yüksektir. Bu yüzden stdev en aza indirilmelidir. Şimdi, sınıf yönteminin çağrılmasıyla ilgilendiğimize göre raporları bir dosyaya yazmayı düşünelim.

Daha önce, raporu oluşturan sınıf yöntemlerinden bahsetmiştim. Şimdi nerede ve ne zaman çağrılacaklarını göreceğiz. Raporlar yalnızca Uzman Danışman tek bir çalıştırma için başlatıldığında oluşturulmalıdır. Aksi takdirde, Uzman Danışman dosyaları optimizasyon modunda oluşturacaktır; yani bir dosya yerine çok sayıda dosya oluşturacaktır (her seferinde farklı dosya adları iletiliyorsa) veya bir dosya oluşturacaktır ancak sonuncu dosya tüm işlemlerde aynı ada sahip olacaktır ki bu çok anlamsızdır, çünkü daha da silinen bilgi için kaynağı boşa harcar..

Yine de optimizasyon sırasında rapor dosyaları oluşturmamalısınız. Farklı adlara sahip çok sayıda dosya alırsanız muhtemelen çoğunu açmayacaksınız. İkinci varyant, hemen silinen bilgileri almak için kaynak israfı yapar.

Bu yüzden en iyi varyant, filtre yapmaktır (raporu sadece Optimization[disabled] modunda başlatın). Böylece HDD, hiçbir zaman görüntülenmeyen raporlarla dolup taşmaz. Ayrıca optimizasyon hızı artar (en yavaş işlemlerin dosya işlemleri olduğu bir sır değildir); ayrıca gerekli parametrelerle hızlı bir şekilde rapor alma imkanı da elde tutulur. Aslında, OnTester'da veya OnDeinit fonksiyonunda filtrenin nereye yerleştirileceği önemli değildir. Önemli olan, raporu oluşturan sınıf yöntemlerinin, dönüşümü gerçekleştiren ana yöntemlerden sonra çağrılmasıdır. Kodu aşırı yüklememek için filtreyi OnDeinit() öğesine yerleştirdim:

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(!(bool)MQL5InfoInteger(MQL5_OPTIMIZATION))
     {
      start.WriteFileDeals();      // writing csv report on deals
      start.WriteFileTrades();     // writing csv report on trades
      start.WriteFileTrades_all(); // writing summary csv report on fitness functions
      start.WriteFileDealsHTML2(); // writing html report on deals
      start.WriteFileTradesHTML2();// writing html report on trades
     }
  }
//+------------------------------------------------------------------+

Yöntemleri çağırma sırası önemli değildir. Raporların yapılması için gerekli olan her şey OnPosStat ve OnTradesStat yöntemlerinde hazırlanır. Ayrıca, rapor yazmanın tüm yöntemlerini veya sadece bazılarını çağırmanız da fark etmez; her birinin çalışması bireyseldir; zaten sınıfta depolanmış olan bilgilerin bir yorumudur.

Strateji Test Cihazını Kontrol Etme

Strateji test cihazında tek bir çalıştırmanın sonucu aşağıda verilmiştir:

Alım Satım Raporu Hareketli Ortalama İstatistikleri
# Bilet tür hacim Açılış Kapanış Fiyat Verimlilik
açılış kapanış fiyat süre fiyat süre maks. min. giriş çıkış alım satım
pos[0] kimlik 2 EURUSD
0 2 3 alış 0,1 1,37203 2010.03.15 13:00:00 1,37169 2010.03.15 14:00:00 1,37236 1,37063 0,19075 0,61272 -0,19653
pos[1] kimlik 4 EURUSD
1 4 5 satış 0,1 1,35188 2010.03.23 08:00:00 1,35243 2010.03.23 10:00:00 1,35292 1,35025 0,61049 0,18352 -0,20599
pos[2] kimlik 6 EURUSD
2 6 7 satış 0,1 1,35050 2010.03.23 12:00:00 1,35343 2010.03.23 16:00:00 1,35600 1,34755 0,34911 0,30414 -0,34675
pos[3] kimlik 8 EURUSD
3 8 9 satış 0,1 1,35167 2010.03.23 18:00:00 1,33343 2010.03.26 05:00:00 1,35240 1,32671 0,97158 0,73842 0,71000
pos[4] kimlik 10 EURUSD
4 10 11 satış 0,1 1,34436 2010.03.30 16:00:00 1,33616 2010.04.08 23:00:00 1,35904 1,32821 0,52384 0,74213 0,26597
pos[5] kimlik 12 EURUSD
5 12 13 alış 0,1 1,35881 2010.04.13 08:00:00 1,35936 2010.04.15 10:00:00 1,36780 1,35463 0,68261 0,35915 0,04176
pos[6] kimlik 14 EURUSD
6 14 15 satış 0,1 1,34735 2010.04.20 04:00:00 1,34807 2010.04.20 10:00:00 1,34890 1,34492 0,61055 0,20854 -0,18090
pos[7] kimlik 16 EURUSD
7 16 17 satış 0,1 1,34432 2010.04.20 18:00:00 1,33619 2010.04.23 17:00:00 1,34491 1,32016 0,97616 0,35232 0,32848
pos[8] kimlik 18 EURUSD
8 18 19 satış 0,1 1,33472 2010.04.27 10:00:00 1,32174 2010.04.29 05:00:00 1,33677 1,31141 0,91916 0,59267 0,51183
pos[9] kimlik 20 EURUSD
9 20 21 satış 0,1 1,32237 2010.05.03 04:00:00 1,27336 2010.05.07 20:00:00 1,32525 1,25270 0,96030 0,71523 0i67553

Etkililik Raporu
Uygunluk Fonksiyonu Ortalama Değer Standart Sapma
Giriş 0,68 0,26
Çıkış 0,48 0,21
Alım satımlar 0,16 0,37


Denge grafiği:


Grafikte optimizasyonun özel fonksiyonunun, daha fazla miktarda sözleşme içeren parametreleri değil de uzun süreli sözleşmeleri içeren parametreleri seçmeye çalıştığını, bu durumda sözleşmelerin neredeyse aynı kâra sahip olduğunu, yani dağılımın yüksek olmadığını açıkça görebilirsiniz.

Hareketli Ortalamalar kodu, pozisyon hacmini artırma veya kısmen kapatma özelliklerini içermediğinden, dönüşümün sonucu yukarıda açıklanana yakın görünmemektedir. Aşağıda, özellikle kodları test etmek için açılan hesapta komut dosyasını başlatmanın başka bir sonucunu bulabilirsiniz:

pos[286] kimlik 1019514 EURUSD
944 1092288 1092289 alış 0,1 1,26733 2010.07.08 21:14:49 1,26719 2010.07.08 21:14:57 1,26752 1,26703 0,38776 0,32653 -0,28571
pos[287] kimlik 1019544 EURUSD
945 1092317 1092322 satış 0,2 1,26761 2010.07.08 21:21:14 1,26767 2010.07.08 21:22:29 1,26781 1,26749 0,37500 0,43750 -0,18750
946 1092317 1092330 satış 0,2 1,26761 2010.07.08 21:21:14 1,26792 2010.07.08 21:24:05 1,26782 1,26749 0,36364 -0,30303 -0,93939
947 1092319 1092330 satış 0,3 1,26761 2010.07.08 21:21:37 1,26792 2010.07.08 21:24:05 1,26782 1,26749 0,36364 -0,30303 -0,93939
pos[288] kimlik 1019623 EURUSD
948 1092394 1092406 alış 0,1 1,26832 2010.07.08 21:36:43 1,26843 2010.07.08 21:37:38 1,26882 1,26813 0,72464 0,43478 0,15942
pos[289] kimlik 1019641 EURUSD
949 1092413 1092417 alış 0,1 1,26847 2010.07.08 21:38:19 1,26852 2010.07.08 21:38:51 1,26910 1,26829 0,77778 0,28395 0,06173
950 1092417 1092433 satış 0,1 1,26852 2010.07.08 21:38:51 1,26922 2010.07.08 21:39:58 1,26916 1,26829 0,26437 -0,06897 -0,80460
pos[290] kimlik 1150923 EURUSD
951 1226007 1226046 alış 0,2 1,31653 2010.08.05 16:06:20 1,31682 2010.08.05 16:10:53 1,31706 1,31611 0,55789 0,74737 0,30526
952 1226024 1226046 alış 0,3 1,31632 2010.08.05 16:08:31 1,31682 2010.08.05 16:10:53 1,31706 1,31611 0,77895 0,74737 0,52632
953 1226046 1226066 satış 0,1 1,31682 2010.08.05 16:10:53 1,31756 2010.08.05 16:12:49 1,31750 1,31647 0,33981 -0,05825 -0,71845
954 1226046 1226078 satış 0,2 1,31682 2010.08.05 16:10:53 1,31744 2010.08.05 16:15:16 1,31750 1,31647 0,33981 0,05825 -0,60194
pos[291] kimlik 1155527 EURUSD
955 1230640 1232744 satış 0,1 1,31671 2010.08.06 13:52:11 1,32923 2010.08.06 17:39:50 1,33327 1,31648 0,01370 0,24062 -0,74568
956 1231369 1232744 satış 0,1 1,32584 2010.08.06 14:54:53 1,32923 2010.08.06 17:39:50 1,33327 1,32518 0,08158 0,49938 -0,41904
957 1231455 1232744 satış 0,1 1,32732 2010.08.06 14:58:13 1,32923 2010.08.06 17:39:50 1,33327 1,32539 0,24492 0,51269 -0,24239
958 1231476 1232744 satış 0,1 1,32685 2010.08.06 14:59:47 1,32923 2010.08.06 17:39:50 1,33327 1,32539 0,18528 0,51269 -0,30203
959 1231484 1232744 satış 0,2 1,32686 2010.08.06 15:00:20 1,32923 2010.08.06 17:39:50 1,33327 1,32539 0,18655 0,51269 -0,30076
960 1231926 1232744 satış 0,4 1,33009 2010.08.06 15:57:32 1,32923 2010.08.06 17:39:50 1,33327 1,32806 0,38964 0,77543 0,16507
961 1232591 1232748 satış 0,4 1,33123 2010.08.06 17:11:29 1,32850 2010.08.06 17:40:40 1,33129 1,32806 0,98142 0,86378 0,84520
962 1232591 1232754 satış 0,4 1,33123 2010.08.06 17:11:29 1,32829 2010.08.06 17:42:14 1,33129 1,32796 0,98198 0,90090 0,88288
963 1232591 1232757 satış 0,2 1,33123 2010.08.06 17:11:29 1,32839 2010.08.06 17:43:15 1,33129 1,32796 0,98198 0,87087 0,85285
pos[292] kimlik 1167490 EURUSD
964 1242941 1243332 satış 0,1 1,31001 2010.08.10 15:54:51 1,30867 2010.08.10 17:17:51 1,31037 1,30742 0,87797 0,57627 0,45424
965 1242944 1243333 satış 0,1 1,30988 2010.08.10 15:55:03 1,30867 2010.08.10 17:17:55 1,31037 1,30742 0,83390 0,57627 0,41017
pos[293] kimlik 1291817 EURUSD
966 1367532 1367788 satış 0,4 1,28904 2010.09.06 00:24:01 1,28768 2010.09.06 02:53:21 1,28965 1,28710 0,76078 0,77255 0,53333


Dönüştürülen bilgi böyle görünür; Okuyuculara her şeyi bilinçli olarak düşünme olanağı vermek için (anlamak, karşılaştırma yoluyla gelir), sözleşmelerin orijinal geçmişini ayrı bir dosyaya kaydediyorum; MetaTrader 4'ün [Results] bölümünde bunu görmeye alışkın olan birçok yatırımcının artık gözden kaçırdığı geçmiş budur.

Sonuç

Sonuç olarak geliştiricilere, Uzman Danışmanları yalnızca özel bir parametreyle değil, aynı zamanda diğer optimizasyon fonksiyonlarında olduğu gibi standart olanlarla kombinasyon halinde yapma olanağı eklemelerini önermek istiyorum. Bu makaleyi özetlersek, sadece temelleri, başlangıç potansiyelini içerdiğini söyleyebilirim; umarım okuyucular sınıfı kendi ihtiyaçlarına göre geliştirebilirler. İyi şanslar!

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

Ekli dosyalar |
posstat.mq5 (1.71 KB)
Bill Williams'ın "Yeni Ticaret Boyutları" kitabına dayanan Uzman Danışman Bill Williams'ın "Yeni Ticaret Boyutları" kitabına dayanan Uzman Danışman
Bu makalede, Uzman Danışmanın Bill Williams tarafından yazılan "New Trading Dimensions: How to Profit from Chaos in Stocks, Bonds and Commodities” (Yeni Ticaret Boyutları: Hisse Senetleri, Tahviller ve Emtialardaki Kaostan Nasıl Kar Edilir) kitabına dayanarak geliştirilmesini ele alacağım. Stratejinin kendisi iyi bilinmektedir ve kullanımı yatırımcılar arasında hala tartışmalıdır. Makale, sistemin alım satım sinyallerini, uygulanmasının özelliklerini ve geçmiş veriler üzerinde test sonuçlarını dikkate almaktadır.
MQL5'te Trend Bulmanın Birkaç Yolu MQL5'te Trend Bulmanın Birkaç Yolu
Herhangi bir yatırımcı, herhangi bir zamanda bir trendi doğru bir şekilde tespit etme fırsatı için çok şey verir. Belki de herkesin aradığı Kutsal Kase budur. Bu makalede bir trendi tespit etmenin birkaç yolunu ele alacağız. Daha net olmak gerekirse MQL5 aracılığıyla bir trendi tespit etmek için birkaç klasik yolun nasıl programlanacağına bakacağız.
Uyarlanabilir Alım Satım Sistemleri ve Bunların MetaTrader 5 Müşteri Terminalinde Kullanımları Uyarlanabilir Alım Satım Sistemleri ve Bunların MetaTrader 5 Müşteri Terminalinde Kullanımları
Bu makale, her biri kendi "sanal" alım satım işlemlerini gerçekleştiren birçok stratejiden oluşan uyarlanabilir bir sistemin bir varyantını önermektedir. Şu anda gerçek alım satım en kârlı stratejinin sinyallerine göre gerçekleştirilir. Nesne yönelimli yaklaşımın kullanılması, verilerle çalışmak için sınıfların olması ve Standart kütüphanenin alım-satım sınıfları sayesinde sistemin mimarisi basit ve ölçeklenebilir görünüyordu; Artık yüzlerce alım satım stratejisini içeren uyarlanabilir sistemleri kolayca oluşturmak ve analiz etmek mümkün.
MQL5'te Çok Renkli Göstergeler Oluşturma MQL5'te Çok Renkli Göstergeler Oluşturma
Bu makalemizde çok renkli göstergelerin nasıl oluşturulacağını veya var olan göstergelerin çok renkli hale nasıl dönüştürüleceğini ele alacağız. MQL5, bilgilerin uygun biçimde temsil edilmesini sağlar. Artık göstergelere sahip bir düzine grafiğe bakmak ve RSI veya Stokastik seviyelerinin analizlerini yapmak gerekli değildir, sadece göstergelerin değerlerine bağlı olarak mumları farklı renklerle boyamak daha iyidir.