Alım Satım Sistemlerinin Değerlendirilmesi - Genel Olarak Giriş, Çıkış ve İşlemlerin Etkililiği
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
- Ücretsiz ticaret uygulamaları
- İşlem kopyalama için 8.000'den fazla sinyal
- Finansal piyasaları keşfetmek için ekonomik haberler
Gizlilik ve Veri Koruma Politikasını ve MQL5.com Kullanım Şartlarını kabul edersiniz