English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Piyasa ve global modellerinin fiziği

Piyasa ve global modellerinin fiziği

MetaTrader 5Ticaret sistemleri | 26 Mart 2024, 14:17
143 0
Evgeniy Ilin
Evgeniy Ilin

Giriş

Bu makalede, piyasa fiziğinin otomatik ticaret için nasıl kullanılabileceğini anlamaya çalışacağız. Matematiğin dili, soyutluk ve belirsizlikten tahmine geçişi ifade eder. Bu, oluşturulan sistemlerin kalitesini artırmak amacıyla bazı yaklaşık ve belirsiz değerler yerine net formüller veya kriterlerle çalışmaya olanak tanır. Herhangi bir teori veya model icat etmeyeceğim, sadece bilinen gerçekleri kullanacağım ve bu gerçekleri kademeli olarak matematiksel analiz diline çevireceğim. Piyasa fiziği matematik olmadan imkansızdır, çünkü ürettiğimiz sinyaller matematiksel bir maddedir. Birçok kişi herhangi bir istatistiksel analiz yapmadan veya çok sınırlı istatistikler kullanarak çeşitli teoriler ve formüller oluşturmaya çalışmaktadır ki bu da genellikle bu tür iddialı sonuçlar için yeterli değildir. Gerçeğin ölçütü yalnızca pratiktir. Önce biraz düşünmeye çalışacağım ve ardından bu düşüncelere dayanarak bir Uzman Danışman oluşturacağım. Bunu Uzman Danışman testi takip edecektir.


Fiyat ve ne sağladığı

Herhangi bir piyasa içeriği, çeşitli ürünlerin varlığına işaret eder. Döviz piyasasında ürün para birimidir. Para birimi, tüm dünyada bir ölçüt olarak belirlenen belirli bir ürüne veya bilgiye sahip olma hakkı anlamına gelir. Örneğin EURUSD çiftini ve grafiğinin mevcut değerini düşünelim. Mevcut grafik değeri USD/EUR = MevcutFiyat anlamına gelecektir. Ya da: USD = EUR*MevcutFiyat, yani bir euroda bulunan dolar miktarı. Başka bir deyişle, değer her bir para biriminin ağırlığının oranını gösterir; elbette her bir para birimi için ortak bir değişim eşdeğeri, yani ortak bir emtia veya başka bir şey olduğu varsayılır. Fiyat, emir defterinde oluşur ve emir defterinin dinamikleri fiyat hareketini belirler. Fiyat oluşumundaki tüm faktörleri hesaba katmamızın mümkün olamayacağı her zaman hatırlanmalıdır. Örneğin, FORTS, forex ile bağlantılıdır ve her iki piyasa da birbirini etkilemektedir. Bu çeşitlilikte bir uzman değilim, ancak her şeyin bağlı olduğunu ve ne kadar çok veri kanalı olursa o kadar iyi olduğunu anlayabiliyorum. Bana öyle geliyor ki, bu kadar ayrıntıya girmemek, fiyatı hareket ettiren basit şeylere odaklanmak daha iyi.

Herhangi bir bağımlılık (fiyat gibi), birçok değişkenin bir fonksiyonu olarak temsil edilebilir. Başlangıçta fiyat şu şekildedir:

  • P = P(t)

Diğer bir deyişle, fiyat zamanın bir fonksiyonudur. Fonksiyonun formu her bir döviz çifti veya başka bir enstrüman için güvenilir bir şekilde belirlenemez, çünkü bu sonsuz bir zaman alacaktır. Ancak bu sunum bize hiçbir şey vermiyor. Bununla birlikte, fiyat hem öngörülebilir hem de rastgele bir bileşene sahip olduğu için ikili bir doğaya sahiptir. Tahmin edilebilir kısım fonksiyonun kendisi değil, birinci zaman türevidir. Bu fonksiyonu bazı terimler olarak temsil etmenin bir anlamı yoktur, çünkü bunun ticaret için bir amacı yoktur. Ancak birinci türevini ele alırsak, aşağıdaki durum ortaya çıkar:

  • P'(t) = Pa'(t)+Pu'(t)

Burada ilk terim matematiksel analiz kullanılarak bir şekilde analiz edilebilen kısmı, ikincisi ise tahmin edilemeyen kısmı yansıtmaktadır. Bu formüle dayanarak, hareketin boyutunu ve yönünü %100 doğrulukla tahmin etmenin mümkün olmadığını söyleyebiliriz. Son terimin ne olacağını düşünmemize gerek yok, çünkü bunu belirleyemeyiz. Ancak ilkini belirleyebiliriz. Değer fonksiyonunun ayrık olduğu ve diferansiyel işlemleri uygulayamayacağımız dikkate alınarak, bu terimin farklı bir biçimde temsil edilebileceği varsayılabilir. Ancak bunun yerine, zaman içindeki ortalama türev "st"yi alabiliriz. Fiyata uygulandığında, bu bir çubuğun süresi olacaktır; tiklere uygulandığında ise, iki tik arasındaki minimum süre olacaktır.

  • PaM(t) = (Pa(t)-Pa(t-st))/st - belirli bir süre boyuncaki ortalama fiyat hareketi (zaman türevi)
  • Ma(t) = Ma(P(t), P(t-st)+...+P(t-N*st), D(t), D(t-st)+...+D(t-N*st), U[1](), U[2](t)+...+U[N](t))
  • P(t[i]) - eski fiyat değerleri (çubuk veya tik verileri)
  • D(t[i]) - diğer döviz çiftlerindeki eski fiyat değerleri
  • U[i](t) - piyasayı etkileyen diğer bilinmeyen veya bilinen değerler
  • Ma(t) - zamanın belirli bir noktasındaki PaM(t) değerinin matematiksel beklentisi 

Başka bir deyişle, fiyatın öngörülebilir kısmının önceki çubuklara veya tiklere, ayrıca diğer döviz çiftlerinin fiyat verilerine, diğer borsalardan gelen verilere ve dünya olaylarına bağlı olabileceğini varsayıyoruz. Ancak, fiyatın bu kısmının bile %100 doğrulukla tahmin edilemeyeceği, ancak bazı özelliklerini hesaplayabileceğimiz anlaşılmalıdır. Böyle bir özellik, matematiksel beklenti, varyans, standart sapma ve olasılık teorisinin diğer nicelikleri gibi rastgele bir değişkenin yalnızca bir olasılığı veya parametreleri olabilir. Matematiksel beklentilere göre davranmak, ticareti kârlı hale getirmek için yeterli olabilir. Zaman ayırıp dikkatlice düşündükten sonra, piyasanın sadece bu mantıkla analiz edilemeyeceği sonucuna varabiliriz. Mesele şu ki, fiyatın öngörülebilir kısmı piyasa katılımcılarının faaliyetlerine bağlı olarak gelişir. Piyasa katılımcılarının kendileri tarafından yaratılan faktörler dışında çeşitli piyasa parametrelerini göz ardı edebiliriz. Elbette tüm bunlar analiz yöntemimizin güvenilirliğinin azalmasına yol açar, ancak bu durum modeli büyük ölçüde basitleştirir. Burada, "st" değeri ne kadar küçük olursa, formüllerimiz piyasayı o kadar doğru tanımlar.

  • VMa(t) = VMa(P(t), P(t-st)+...+P(t-N*st))
  • VMa(t) = VBuy(t)-VSell(t)
  • VMa(t) - toplam hacimler
  • VBuy(t) - açık Alış emirlerinin hacimleri
  • VSell(t) - açık Satış emirlerinin hacimleri

Yukarıdaki fonksiyon, o anda açık olan tüm Alış ve Satış pozisyonlarının hacimlerindeki farkı tanımlar. Bu pozisyonların bir kısmı birbirini telafi ederken, geri kalan pozisyonlar bağımsızdır. Pozisyonlar açık olduğu için bir süre sonra kapanacağına dair bir vaadi simgelemektedir. Hepimiz satın almanın fiyatı yükselttiğini, satmanın ise fiyatı düşürdüğünü biliyoruz. Fiyatın nereye gideceğini bilmenin tek yolu, açık pozisyonların hacimlerini ölçmek ve yalnızca açık piyasa emirlerini dikkate alarak bu pozisyonların yönünü tahmin etmektir.

Piyasanın dalga niteliği aslında bu basit gerçekle bağlantılıdır. Bu, pozisyon hacimlerindeki dalgalanmalar ya da boğa ve ayıların eylemleri gibi daha genel bir sürecin yalnızca özel bir durumudur.

Çubuklarla uğraşırken, bir çubuğun içerisinde 4 fiyat olduğu gerçeğini de hesaba katmak mümkündür, bu da bize daha iyi formüller verebilir. Daha fazla veri daha doğru analiz anlamına gelir, bu nedenle tüm fiyat verilerini dikkate almak önemlidir. Ancak, algoritmaları on kat yavaşlatacağı için her tikin sayılmasını sevmiyorum. Ayrıca, tik verileri farklı brokerlarda farklı olabilir. Aksine, çubuk açılış ve kapanış fiyatları çoğu broker için neredeyse aynıdır. Hacim fonksiyonunu tüm fiyat verilerini dikkate alacak şekilde değiştirelim:

  • VMa(t) = VMa(O(t), O(t-st)+...+O(t-N*st), C(t), C(t-st)+...+C(t-N*st), H(t), H(t-st)+...+H(t-N*st), L(t), L(t-st)+...+L(t-N*st))

Bu fonksiyona zaman, günler, haftalar ve aylar gibi daha fazla değişken ekleyebiliriz, ancak bu belirli piyasa alanlarına bağlı çok sayıda fonksiyon üretecektir, oysa bizim amacımız genel piyasa fiziğini belirlemektir. Bunun bozulamayacağını ve dolayısıyla piyasa var olduğu sürece kullanılabileceğini bileceğiz. Formülün bir diğer avantajı da çok dövizli yapısıdır.

Pratik açıdan, bu temsil türünün kullanımı mantıklı değildir, çünkü bu fonksiyonu tam olarak nasıl ve hangi verilere dayanarak oluşturacağımızı bilmemiz gerekir. Sadece bu fonksiyonun formunu yazıp bağımlılıkları belirleyemeyiz. Ancak bu ifadeler, nasıl analiz edeceğimiz ve aşağıdaki varsayımlara nasıl geçeceğimiz konusunda bir başlangıç anlayışı kazanmamıza yardımcı olabilir. Herhangi bir mantıksal koşul kümesi nihayetinde böyle bir fonksiyon olarak temsil edilebilir. Tersine, fonksiyonun kendisi de bir koşul kümesine dönüştürülebilir. Hangi formu kullandığımız önemli değildir. Önemli olan sadece bunu anlamaktır. Herhangi bir algoritma tek bir formüle indirgenebilir. Bazen sinyalleri koşullar veya koşullar sistemi olarak tanımlamak, süper karmaşık bir fonksiyon oluşturmaktan daha kolaydır. Bir diğer büyük soru da böyle bir fonksiyonun nasıl oluşturulacağıdır.

Gerçek bir ticaret sisteminde, tüm geçmişi bir kerede analiz edemeyiz, ancak yalnızca sabit bir zaman dönemini analiz edebiliriz. Bu tür bir analiz için 4 olası yaklaşım vardır. Onlar için adlar oluşturacağım ve açıklayacağım:

  • Formüller (göstergeler veya fonksiyonları)
  • Simülasyon
  • Genel matematik
  • Makine öğrenimi türleri

İlk seçenek, belirli bir değeri veya bir değerler kümesini kullandığımızı varsayar. Örnek olarak bir gösterge veya kendi formülümüz verilebilir. Bu yaklaşımın avantajı, MetaTrader 4/5 terminallerinde geniş bir araç setinin bulunmasıdır. Ayrıca, popüler piyasa teorilerine dayanan, Mağazada ve webde bulunan çok sayıda gösterge vardır. Bu yaklaşımın dezavantajı, çoğu durumda göstergenin neye dayanarak çalıştığını anlamayacak olmamızdır. Anlasak bile, böyle bir anlayışın hiçbir değeri olamaz.

İkinci seçenekte, anlamadığımız veya hiçbir işe yaramayacak verileri kullanmıyoruz. Bunun yerine, piyasadaki emirleri simüle etmeyi deneyebiliriz ve böylece sistemimizin bir yönde kaç pozisyonun açık olduğunu ve diğer yönde kaç pozisyonun açık olduğunu bir dereceye kadar tanımlayabileceğini bileceğiz. Bu bilgiler gerekli tahminleri üreterek piyasanın global bir perspektifte iyi bir şekilde tanımlanmasını sağlayabilir. Bu, makine öğrenimine tek alternatiftir.

Matematik, mevcut piyasa durumundan bağımsız olarak herhangi bir fiyattan yararlanmaya izin veren bazı temel yasaların anlaşılması veya belirli matematiksel ilkelerin bilinmesi anlamına gelir. Gerçek şu ki, ayrık olanlar da dahil olmak üzere herhangi bir fonksiyon, yararlanılabilecek belirli özelliklere sahiptir. Elbette burada bağımlılığın kaotik olmadığını varsayıyoruz (bizim durumumuzda forex kaotik değildir, bu nedenle herhangi bir fiyattan yararlanılabilir). Bir sonraki makalede, neredeyse herkesin bildiği böyle bir ilkeyi analiz edeceğiz. Ancak bilmek ve kullanabilmek iki farklı şeydir. Bu yaklaşımın avantajı, başarılı bir sistem kurmayı başarırsak, gelecekte nasıl davranacağı konusunda endişelenmemize gerek kalmamasıdır. 

Dördüncü yaklaşım en iyisidir, çünkü makine öğrenimi her türlü veriden en iyi şekilde faydalanabilir. Ne kadar fazla hesaplama gücüne sahip olursanız, analizin kalitesi de o kadar yüksek olur. Bu yaklaşımın dezavantajı, piyasa fiziğini anlamaya yardımcı olmamasıdır. Avantajı, yaklaşımın basitliği, minimum zaman harcayarak maksimum kalitede sonuçlar elde edilmesidir. Ancak bu yaklaşım bu makale kapsamında uygulanabilir değildir.


Modeller hakkında

Bir yatırımcının günlük hayatında, bazıları daha az önemli, bazıları ise son derece önemli olan birçok terim vardır. Bazı terimler çok sık kullanılır, ancak tüm yatırımcılar bunların gerçek amacını anlamaz. Bu terimlerden biri de modeldir (pattern). Bunun ne olduğunu matematik diliyle açıklamaya çalışacağım. Bir model her zaman belirli bir zaman dönemiyle ve belirli bir döviz çifti ve grafik zaman dilimiyle bağlantılıdır. Bazı modeller güçlüdür. Bu tür modeller çok dövizli veya global nitelikte olabilir. İdeal bir model kutsal kasedir. Her modele uygulanabilecek bazı ifadeler vardır:

  • Modeli sembolize eden bir formülün veya bir koşul kümesinin varlığı
  • Strateji sınayıcıdaki minimum test değerleri veya bir demo veya gerçek hesaptaki performans değerleri
  • Modelin tüm döviz çiftleri ve grafik zaman dilimleri için performans açısından sınıflandırılması
  • Modelin bulunduğu geçmiş dönemi
  • Gelecekte, modelin çalışır durumda kalacağı zaman dönemi
  • Gelecekte, orijinal modelin bazı parametreleri koruduğu veya tersine çevirdiği, birincisini takip eden ikinci zaman dönemi

Her bir özelliği dikkatlice okursanız, bir modelin, seçilen aralıklardaki fiyat hareketini en doğru şekilde tanımlayan bir formül veya bir koşul kümesi olduğunu anlayabilirsiniz. Bir model, özellikle çok küçük bir dönemde bulunursa veya ilgili sistem aşırı iyimser değerler üretirse rastgele olabilir. Bir sistemi kısa dönemlerle test ederken, global modelleri bulma şansının sıfıra inme eğiliminde olduğunu anlamak çok önemlidir. Bu durum örneklem büyüklüğü ile bağlantılıdır. Örneklem ne kadar küçük olursa, sonuçların rastgeleliği de o kadar yüksek olur. 

Bir modelin ne olduğunu belirledik. Ancak modeller nasıl etkili bir şekilde kullanılır? Her şey bu modelin nasıl bulunduğuna ve kalitesine bağlıdır. Hesaplama gücünü kullanan analiz yöntemlerini hesaba katmazsak, analitiğe geliriz. Bana göre analitik, herhangi bir makine analizi türüyle rekabet edemez - iyi bir analist ekibi bile tek bir makinenin işleyebileceği verileri işleyemez. Her halükarda, global modelleri bulma süreci hesaplama gücü gerektirir. Bariz şeyleri kendi gözlerinizle gördüğünüz ve fiziklerini anladığınız durumlar hariç.


Basit bir pozisyon simülatörünün yazılması

Global modelleri bulmaya çalışmak için, piyasa katılımcılarının ruh halini tanımlayabilen bir Uzman Danışman geliştirmek ilginç olacaktır. Bunun için bir piyasa pozisyonları simülatörü oluşturmaya karar verdim. Pozisyonlar, piyasa uçlarına yakın çubuklar dahilinde simüle edilecektir. Piyasa katılımcılarının farklı olduğunu ve emirlerinin ağırlığının da farklı olduğunu varsaymak gerekecektir. Aynı zamanda, bu basit bir biçimde sunulmalıdır. Basit bir prototip kâr sağladığını gösterirse, ilkeleri daha fazla kullanılabilir.

Mantık, koşullu olarak 3 ayrı simülasyona ve bunların olası herhangi bir karma kombinasyonuna bölünecektir:

  • Stop emirlerinin simülasyonu
  • Limit emirlerinin simülasyonu
  • Piyasa emirlerinin simülasyonu
  • Olası tüm kombinasyonlar

Emir vermek için aşağıdaki mantık kullanılacaktır:

Emir ızgarası mantığı

Bu ızgaralar, piyasa katılımcılarının bir kısmının ruh halini simüle etmek amacıyla her yeni çubuğa yerleştirilir. Eski emir ızgaralarının durumu, grafikte görünen yeni çubuğa göre güncellenir. Bu yaklaşım çok doğru değildir, ancak tik tik simülasyon sonsuz hesaplamalara yol açacaktır. Dahası, tiklere pek güvenmiyorum.

Göreceli hacimlerin iki tür dağılımı vardır, zayıflamalı ve eşit, ancak yalnızca Stop ve Limit emirleri için. Piyasa emirleri eşit dağılıma sahiptir. Bu perspektiften bakıldığında, dağılım türlerini genişletmek de mümkün olacaktır. Dağılımın görsel sunumu:

Göreceli hacim türleri

Burada, emri simgeleyen çizginin uzunluğu aynı emrin hacmiyle orantılıdır. Bu tür çizimlerin herkes için basit ve anlaşılır olacağını düşünüyorum.

Bu durumda, her şey nesne yönelimli bir yaklaşım kullanılarak yapılabilir. Numaralandırılmış listeleri tanımlayarak başlayalım:

enum CLOSE_MODE// how to close orders
   {
   CLOSE_FAST,// fast
   CLOSE_QUALITY// wait for an opposite signal
   };

enum WORK_MODE// operation mode
   {
   MODE_SIMPLE,// slow mode
   MODE_FAST// fast mode
   };

enum ENUM_GRID_WEIGHT//weight fill type for limit and stop orders
   {
   WEIGHT_DECREASE,// with attenuation if moving from the price
   WEIGHT_SAME// the same for the entire grid
   };

enum ENUM_STATUS_ORDER// statuses of orders or positions
   {
   STATUS_VIRTUAL,// stop or limit order
   STATUS_MARKET,// market order
   STATUS_ABORTED// canceled stop or limit order
   };

Simülatör yavaş ve hızlı olmak üzere iki modda çalışacaktır. Yavaş mod esas olarak başlangıç analizi için gereklidir. Başlangıç analizinde, hesaplama piyasa mumlarına en yakın ilk "n" içerisinde gerçekleştirilir. Hızlı modda, hesaplama yalnızca yeni ortaya çıkan mum üzerinde gerçekleştirilir. Ancak bu basit yaklaşımın yeterli olmadığı ortaya çıktı. Algoritma hızını artırmak için ek bir işlevsellik gerekliydi. Uzman Danışman başlatılırken oldukça büyük bir hesaplama gerçekleştirilir. Ancak o zaman simülasyonu her mumda yalnızca bir yeni mum için güncellememiz gerekir. Her çubuk için mevcut piyasa fiyatına (Open[i]) olan mesafeye bağlı olarak limit ve stop emirleri için iki tür hacim dağılımı olacaktır. Bunun nedeni, her çubukta farklı dağılımlar ve ağırlıklarla bir stop ve limit emirleri ızgarasının açılmasıdır. Bir süre sonra stop ve limit emirleri piyasa emirlerine dönüşür. Fiyat belirtilen süre içinde istenen fiyata ulaşmazsa, stop ve limit emirleri iptal edilir.

Bu simülasyonu basitten karmaşığa doğru, yavaş yavaş her şeyi bir araya getirerek oluşturmaya başlayalım. İlk olarak, emrin ne olduğunu tanımlayalım:

struct Order// structure symbolizing a player's order
   {
   public:
   double WantedPrice;// desired open price
   int BarsExpirationOpen;// If the order remains for certain number of bars, the player can't wait any more and cancels the order
   int BarsExpirationClose;//If this is a market order and the player does not want to wait, he closes the position
   double UpPriceToClose;//The total upward price movement at which the player closes the order (points)
   double LowPriceToClose;//The total downward price movement at which the player closes the order 
   double VolumeAlpha;// current volume equivalent [0...1]
   double VolumeStart;// starting volume equivalent [0...1]
   int IndexMarket;// the index of the bar on which the virtual market turned into market
   ENUM_STATUS_ORDER Status;// order status
   Order(ENUM_STATUS_ORDER S)// constructor that creates a certain order
      {
      Status=S;
      }
   };

Çok fazla parametre yoktur ve her parametre genel algoritma için önemlidir. Alanların çoğu herhangi bir emir için uygulanabilirken, bazıları yalnızca Limit veya Stop emirleri için geçerlidir. Örneğin, istenen fiyat bir piyasa emri için açılış fiyatı iken, Limit ve Stop emirleri için tam olarak istenen fiyattır.

Üst ve alt kapanış fiyatları durma seviyeleri olarak işlev görür. Aynı zamanda, ızgara emrinin tam olarak bir emir olmadığını ve bu emrin bir grup emir içerdiğini, ancak belirli bir fiyattan belirli bir hacimle açılan tek bir emirde birleştiklerini varsayacağız. Başlangıç hacmi ve mevcut hacim değişkenleri bize emirlerin belirli bir çubuğun belirli bir seviyesinde ne kadar önemli olduğunu söyler.

Başlangıç hacmi, emrin yerleştirildiği andaki hacimdir. Mevcut hacim, olaylar daha da geliştikçe oluşan hacimdir. Önemli olan, belirli emirlerden elde edilen kârlardan ziyade Alış ve Satış emirlerinin hacimlerinin oranıdır. İşlem sinyalleri bu hususlara göre oluşturulacaktır. Elbette başka sinyaller de bulabiliriz, ancak bunun için başka hususlara dikkat etmek gerekir. Ayrıca, emirlerin belirli seviyelere ulaştıklarında kapatılmayacağını, ancak olayların gerçek gelişimini mümkün olduğunca simüle etmek amacıyla kapanışın her çubukta kademeli olarak gerçekleşeceğini unutmayın.

Ardından, her bir çubuk için depolama alanını tanımlamamız gerekir. Çubuk, üzerinde açılan emirleri depolayacaktır:

class OrderBox// Order box of a specific bar
   {
   public:
   Order BuyStopOrders[];
   Order BuyLimitOrders[];
   Order BuyMarketOrders[];
   Order SellStopOrders[];
   Order SellLimitOrders[];
   Order SellMarketOrders[];
   
   OrderBox(int OrdersToOneBar)
      {
      ArrayResize(BuyStopOrders,OrdersToOneBar);
      ArrayResize(BuyLimitOrders,OrdersToOneBar);
      ArrayResize(BuyMarketOrders,OrdersToOneBar);
      ArrayResize(SellStopOrders,OrdersToOneBar);
      ArrayResize(SellLimitOrders,OrdersToOneBar);
      ArrayResize(SellMarketOrders,OrdersToOneBar);      
      for ( int i=0; i<ArraySize(BuyStopOrders); i++ )// Set types for all orders
         {
         BuyStopOrders[i]=Order(STATUS_VIRTUAL);
         BuyLimitOrders[i]=Order(STATUS_VIRTUAL);
         BuyMarketOrders[i]=Order(STATUS_MARKET);
         SellStopOrders[i]=Order(STATUS_VIRTUAL);
         SellLimitOrders[i]=Order(STATUS_VIRTUAL);
         SellMarketOrders[i]=Order(STATUS_MARKET);         
         }
      }
   };

Burada her şey oldukça basit. Dizilerle tanımlanan altı tür emir vardır. Bu, karışıklığı önlemek için yapılmıştır. Elbette bu sınıfı saf haliyle kullanmayacağız, bu sadece yapıdaki bir tuğladır.

Ardından, tüm çubukların ortak depolama alanını, daha sonra kalıtımın gerçekleştirileceği tek bir nesne olarak tanımlıyoruz. Buradaki teknikler oldukça basittir.

class BarBox// Storage for all orders
   {
   protected:
   OrderBox BarOrders[];
   
   BarBox(int OrdersToOneBar,int BarsTotal)
      {
      ArrayResize(BarOrders,BarsTotal);
      for ( int i=0; i<ArraySize(BarOrders); i++ )// Set types for all orders
         {
         BarOrders[i]=OrderBox(OrdersToOneBar);
         }
      }   
   };

Bu sadece çubuk verilerini (emirleri) içeren bir depodur, başka bir şey değildir. Şimdiye kadar her şey oldukça anlaşılır. İlerleyen kısımlarda işler daha da karmaşık bir hal alacaktır.

Emirler için uygun bir veri deposu belirledikten sonra, emirlerin nasıl ve hangi kurallara göre oluşturulduğunu, belirli emir türlerinin öneminin ne olduğunu vb. belirlememiz gerekir. Bu amaç için aşağıdaki sınıfı oluşturdum:

class PositionGenerator:public BarBox// Inherit class from the box to avoid the need to include it as an internal member and to avoid multiple references
   {
   protected:
   double VolumeAlphaStop;// importance of volumes of STOP orders
   double VolumeAlphaLimit;// importance of volumes of LIMIT orders
   double VolumeAlphaMarket;// importance of volumes of MARKET orders
   double HalfCorridorLimitStop;// step of the corridor of Limit and Stop orders in points
   int ExpirationOpenLimit;// after how many bars the volumes of the grid of limit orders for opening will completely attenuate
   int ExpirationOpenStop;// after how many bars the volumes of the grid of stop orders for opening will completely attenuate
   int ExpirationClose;// after how many bars the volumes of orders for closing will completely attenuate
   int ProfitPointsCorridorPart;// half corridor size for the profit of all orders
   int LossPointsCorridorPart;// half corridor size for the loss of all orders
   int OrdersToOneBar;// orders of one type per 1 bar
   ENUM_GRID_WEIGHT WeightStopLimitFillingType;
   
   PositionGenerator( ENUM_GRID_WEIGHT WeightStopLimitFillingType0
                     ,int HalfCorridorLimitStop0,int OrdersToOneBar0,int BarsTotal0
                     ,int ExpirationOpenLimit0,int ExpirationOpenStop0
                     ,int ExpirationClose0
                     ,int ProfitPointsCorridorPart0,int LossPointsCorridorPart0
                     ,double VolumeAlphaStop0,double VolumeAlphaLimit0,double VolumeAlphaMarket0) 
                     : BarBox(OrdersToOneBar0,BarsTotal0)
      {
      VolumeAlphaStop=VolumeAlphaStop0;
      VolumeAlphaLimit=VolumeAlphaLimit0;
      VolumeAlphaMarket=VolumeAlphaMarket0;
      OrdersToOneBar=OrdersToOneBar0;
      HalfCorridorLimitStop=double(HalfCorridorLimitStop0)/double(OrdersToOneBar);
      ExpirationOpenLimit=ExpirationOpenLimit0;
      ExpirationOpenStop=ExpirationOpenStop0;
      ExpirationClose=ExpirationClose0;
      ProfitPointsCorridorPart=ProfitPointsCorridorPart0;
      LossPointsCorridorPart=LossPointsCorridorPart0;
      OrdersToOneBar=OrdersToOneBar0;
      WeightStopLimitFillingType=WeightStopLimitFillingType0;
      }
   private:
   
   double CalcVolumeDecrease(double TypeWeight,int i,int size)// attenuation volume
      {
      if ( size > 1 )
         {
         double K=1.0/(1.0-size);
         double C=1.0;
         return TypeWeight*K*i+C;
         }
      else return 0.0;
      }
      
   double CalcVolumeSimple(double TypeWeight)// equal volume
      {
      return TypeWeight;
      }
   
   void RebuildStops()// rebuild stop orders
      {
      int size=ArraySize(BarOrders[0].BuyStopOrders);
      for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
         {
         for ( int i=0; i<size; i++ )// reset all
            {
            BarOrders[j].BuyStopOrders[i].Status=STATUS_VIRTUAL;// reset status to initial
            BarOrders[j].BuyStopOrders[i].WantedPrice=Open[j+1]+HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
            if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[j].BuyStopOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaStop,i,size);// weight of each element of the grid
            if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[j].BuyStopOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaStop);// current weight of each element of the grid
            BarOrders[j].BuyStopOrders[i].VolumeStart=BarOrders[j].BuyStopOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].BuyStopOrders[i].UpPriceToClose=BarOrders[j].BuyStopOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;// upper border to close
            BarOrders[j].BuyStopOrders[i].LowPriceToClose=BarOrders[j].BuyStopOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
            BarOrders[j].BuyStopOrders[i].BarsExpirationOpen=ExpirationOpenStop;
            BarOrders[j].BuyStopOrders[i].BarsExpirationClose=ExpirationClose;
       
            BarOrders[j].SellStopOrders[i].Status=STATUS_VIRTUAL;
            BarOrders[j].SellStopOrders[i].WantedPrice=Open[j+1]-HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
            if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[j].SellStopOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaStop,i,size);// weight of each element of the grid
            if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[j].SellStopOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaStop);// current weight of each element of the grid
            BarOrders[j].SellStopOrders[i].VolumeStart=BarOrders[j].SellStopOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].SellStopOrders[i].UpPriceToClose=BarOrders[j].SellStopOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
            BarOrders[j].SellStopOrders[i].LowPriceToClose=BarOrders[j].SellStopOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower border to close
            BarOrders[j].SellStopOrders[i].BarsExpirationOpen=ExpirationOpenStop;
            BarOrders[j].SellStopOrders[i].BarsExpirationClose=ExpirationClose;                    
            }         
         }      
      }
      
   void RebuildLimits()// rebuild limit orders
      {
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
         {
         for ( int i=0; i<size; i++ )// reset all
            {
            BarOrders[j].BuyLimitOrders[i].Status=STATUS_VIRTUAL;// reset status to initial
            BarOrders[j].BuyLimitOrders[i].WantedPrice=Open[j+1]-HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
            if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[j].BuyLimitOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaLimit,i,size);// weight of each element of the grid
            if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[j].BuyLimitOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaLimit);// current weight of each element of the grid
            BarOrders[j].BuyLimitOrders[i].VolumeStart=BarOrders[j].BuyLimitOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].BuyLimitOrders[i].UpPriceToClose=BarOrders[j].BuyLimitOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;// upper border to close
            BarOrders[j].BuyLimitOrders[i].LowPriceToClose=BarOrders[j].BuyLimitOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
            BarOrders[j].BuyLimitOrders[i].BarsExpirationOpen=ExpirationOpenLimit;
            BarOrders[j].BuyLimitOrders[i].BarsExpirationClose=ExpirationClose;            
       
            BarOrders[j].SellLimitOrders[i].Status=STATUS_VIRTUAL;
            BarOrders[j].SellLimitOrders[i].WantedPrice=Open[j+1]+HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
            if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[j].SellLimitOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaLimit,i,size);// weight of each element of the grid
            if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[j].SellLimitOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaLimit);// current weight of each element of the grid
            BarOrders[j].SellLimitOrders[i].VolumeStart=BarOrders[j].SellLimitOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].SellLimitOrders[i].UpPriceToClose=BarOrders[j].SellLimitOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
            BarOrders[j].SellLimitOrders[i].LowPriceToClose=BarOrders[j].SellLimitOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower border to close
            BarOrders[j].SellLimitOrders[i].BarsExpirationOpen=ExpirationOpenLimit;
            BarOrders[j].SellLimitOrders[i].BarsExpirationClose=ExpirationClose;
            }         
         }      
      }
      
   void RebuildMarkets()// rebuild market orders
      {
      int size=ArraySize(BarOrders[0].BuyMarketOrders);
      double MarketStep;
      for ( int j=ArraySize(BarOrders)-1; j>0; j-- )
         {
         MarketStep=(High[j+1]-Low[j+1])/double(OrdersToOneBar);
            
         for ( int i=0; i<size; i++ )// reset all
            {
            BarOrders[j].BuyMarketOrders[i].Status=STATUS_MARKET;// reset status to initial
            BarOrders[j].BuyMarketOrders[i].WantedPrice=Low[j+1]+MarketStep*i;// prices of the order grid
            BarOrders[j].BuyMarketOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaMarket);// current weight of each element of the grid
            BarOrders[j].BuyMarketOrders[i].VolumeStart=BarOrders[j].BuyMarketOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].BuyMarketOrders[i].UpPriceToClose=BarOrders[j].BuyMarketOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;// upper border to close
            BarOrders[j].BuyMarketOrders[i].LowPriceToClose=BarOrders[j].BuyMarketOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
            BarOrders[j].BuyMarketOrders[i].BarsExpirationClose=ExpirationClose;
               
            BarOrders[j].SellMarketOrders[i].Status=STATUS_MARKET;
            BarOrders[j].SellMarketOrders[i].WantedPrice=High[j+1]-MarketStep*i;// prices of the order grid
            BarOrders[j].SellMarketOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaMarket);// current weight of each element of the grid
            BarOrders[j].SellMarketOrders[i].VolumeStart=BarOrders[j].SellMarketOrders[i].VolumeAlpha;// starting weight of each element of the grid
            BarOrders[j].SellMarketOrders[i].UpPriceToClose=BarOrders[j].SellMarketOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
            BarOrders[j].SellMarketOrders[i].LowPriceToClose=BarOrders[j].SellMarketOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower border to close
            BarOrders[j].SellMarketOrders[i].BarsExpirationClose=ExpirationClose;
            } 
         }      
      }

   ///// Fast methods
   void RebuildStopsFast()// rebuild stop orders
      {
      int size=ArraySize(BarOrders[0].BuyStopOrders);
      for ( int j=ArraySize(BarOrders)-1; j>0; j-- )
         {
         for ( int i=0; i<size; i++ )// shift orders
            {
            BarOrders[j].BuyStopOrders[i]=BarOrders[j-1].BuyStopOrders[i];
            BarOrders[j].SellStopOrders[i]=BarOrders[j-1].SellStopOrders[i];
            BarOrders[j].SellStopOrders[i].IndexMarket++;
            }
         }
         
      for ( int i=0; i<size; i++ )// create a new grid at a new bar
         {
         BarOrders[0].BuyStopOrders[i].Status=STATUS_VIRTUAL;// reset status to initial
         BarOrders[0].BuyStopOrders[i].WantedPrice=Close[1]+HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
         if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[0].BuyStopOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaStop,i,size);// weight of each element of the grid
         if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[0].BuyStopOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaStop);// current weight of each element of the grid
         BarOrders[0].BuyStopOrders[i].VolumeStart=BarOrders[0].BuyStopOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].BuyStopOrders[i].UpPriceToClose=BarOrders[0].BuyStopOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;//upper border to close
         BarOrders[0].BuyStopOrders[i].LowPriceToClose=BarOrders[0].BuyStopOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
         BarOrders[0].BuyStopOrders[i].BarsExpirationOpen=ExpirationOpenStop;
         BarOrders[0].BuyStopOrders[i].BarsExpirationClose=ExpirationClose;
       
         BarOrders[0].SellStopOrders[i].Status=STATUS_VIRTUAL;
         BarOrders[0].SellStopOrders[i].WantedPrice=Close[1]-HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
         if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[0].SellStopOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaStop,i,size);// weight of each element of the grid
         if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[0].SellStopOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaStop);// current weight of each element of the grid
         BarOrders[0].SellStopOrders[i].VolumeStart=BarOrders[0].SellStopOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].SellStopOrders[i].UpPriceToClose=BarOrders[0].SellStopOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
         BarOrders[0].SellStopOrders[i].LowPriceToClose=BarOrders[0].SellStopOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower border to close
         BarOrders[0].SellStopOrders[i].BarsExpirationOpen=ExpirationOpenStop;
         BarOrders[0].SellStopOrders[i].BarsExpirationClose=ExpirationClose;                    
         }               
      }
      
   void RebuildLimitsFast()// rebuild limit orders
      {
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      for ( int j=ArraySize(BarOrders)-1; j>0; j-- )
         {
         for ( int i=0; i<size; i++ )// shift orders
            {
            BarOrders[j].BuyLimitOrders[i]=BarOrders[j-1].BuyLimitOrders[i];
            BarOrders[j].SellLimitOrders[i]=BarOrders[j-1].SellLimitOrders[i];
            BarOrders[j].SellLimitOrders[i].IndexMarket++;
            }         
         }
      
      for ( int i=0; i<size; i++ )// create a new grid at a new bar
         {
         BarOrders[0].BuyLimitOrders[i].Status=STATUS_VIRTUAL;// reset status to initial
         BarOrders[0].BuyLimitOrders[i].WantedPrice=Open[1]-HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
         if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[0].BuyLimitOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaLimit,i,size);// weight of each element of the grid
         if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[0].BuyLimitOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaLimit);// current weight of each element of the grid
         BarOrders[0].BuyLimitOrders[i].VolumeStart=BarOrders[0].BuyLimitOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].BuyLimitOrders[i].UpPriceToClose=BarOrders[0].BuyLimitOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;// upper border to close
         BarOrders[0].BuyLimitOrders[i].LowPriceToClose=BarOrders[0].BuyLimitOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
         BarOrders[0].BuyLimitOrders[i].BarsExpirationOpen=ExpirationOpenLimit;
         BarOrders[0].BuyLimitOrders[i].BarsExpirationClose=ExpirationClose;            
       
         BarOrders[0].SellLimitOrders[i].Status=STATUS_VIRTUAL;
         BarOrders[0].SellLimitOrders[i].WantedPrice=Open[1]+HalfCorridorLimitStop*(i+1)*Point;// prices of the order grid
         if ( WeightStopLimitFillingType == WEIGHT_DECREASE ) BarOrders[0].SellLimitOrders[i].VolumeAlpha=CalcVolumeDecrease(VolumeAlphaLimit,i,size);// weight of each element of the grid
         if ( WeightStopLimitFillingType == WEIGHT_SAME ) BarOrders[0].SellLimitOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaLimit);// current weight of each element of the grid
         BarOrders[0].SellLimitOrders[i].VolumeStart=BarOrders[0].SellLimitOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].SellLimitOrders[i].UpPriceToClose=BarOrders[0].SellLimitOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
         BarOrders[0].SellLimitOrders[i].LowPriceToClose=BarOrders[0].SellLimitOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower order to close
         BarOrders[0].SellLimitOrders[i].BarsExpirationOpen=ExpirationOpenLimit;
         BarOrders[0].SellLimitOrders[i].BarsExpirationClose=ExpirationClose;
         }        
      }
      
   void RebuildMarketsFast()// rebuild market orders
      {
      int size=ArraySize(BarOrders[0].BuyMarketOrders);
      double MarketStep;
      for ( int j=ArraySize(BarOrders)-1; j>0; j-- )
         {
         for ( int i=0; i<size; i++ )// shift orders
            {
            BarOrders[j].BuyMarketOrders[i]=BarOrders[j-1].BuyMarketOrders[i];
            BarOrders[j].SellMarketOrders[i]=BarOrders[j-1].SellMarketOrders[i];
            }         
         }
      MarketStep=(High[1]-Low[1])/double(OrdersToOneBar);
      for ( int i=0; i<size; i++ )// create a new grid at a new bar
         {
         BarOrders[0].BuyMarketOrders[i].Status=STATUS_MARKET;// reset status to initial
         BarOrders[0].BuyMarketOrders[i].WantedPrice=Low[1]+MarketStep*i;// prices of the order grid
         BarOrders[0].BuyMarketOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaMarket);// current weight of each element of the grid
         BarOrders[0].BuyMarketOrders[i].VolumeStart=BarOrders[0].BuyMarketOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].BuyMarketOrders[i].UpPriceToClose=BarOrders[0].BuyMarketOrders[i].WantedPrice+ProfitPointsCorridorPart*Point;// upper border to close
         BarOrders[0].BuyMarketOrders[i].LowPriceToClose=BarOrders[0].BuyMarketOrders[i].WantedPrice-LossPointsCorridorPart*Point;// lower border to close
         BarOrders[0].BuyMarketOrders[i].BarsExpirationClose=ExpirationClose;
               
         BarOrders[0].SellMarketOrders[i].Status=STATUS_MARKET;
         BarOrders[0].SellMarketOrders[i].WantedPrice=High[1]-MarketStep*i;// prices of the order grid
         BarOrders[0].SellMarketOrders[i].VolumeAlpha=CalcVolumeSimple(VolumeAlphaMarket);// current weight of each element of the grid
         BarOrders[0].SellMarketOrders[i].VolumeStart=BarOrders[0].SellMarketOrders[i].VolumeAlpha;// starting weight of each element of the grid
         BarOrders[0].SellMarketOrders[i].UpPriceToClose=BarOrders[0].SellMarketOrders[i].WantedPrice+LossPointsCorridorPart*Point;// upper border to close
         BarOrders[0].SellMarketOrders[i].LowPriceToClose=BarOrders[0].SellMarketOrders[i].WantedPrice-ProfitPointsCorridorPart*Point;// lower border to close
         BarOrders[0].SellMarketOrders[i].BarsExpirationClose=ExpirationClose;
         }         
      }   
   
   protected:
   void CreateNewOrders()// create new orders at each candlestick
      {
      if ( VolumeAlphaStop != 0.0 ) RebuildStops();
      if ( VolumeAlphaLimit != 0.0 ) RebuildLimits();
      if ( VolumeAlphaMarket != 0.0 ) RebuildMarkets();
      }
   
   void CreateNewOrdersFast()//
      {
      if ( VolumeAlphaStop != 0.0 ) RebuildStopsFast();
      if ( VolumeAlphaLimit != 0.0 ) RebuildLimitsFast();
      if ( VolumeAlphaMarket != 0.0 ) RebuildMarketsFast();      
      }
   
   public:   
   virtual void Update()// state updating function (will be expanded in child classes)
      {
      CreateNewOrders();
      }
      
   virtual void UpdateFast()// fast state update
      {
      CreateNewOrdersFast();
      }      
   };

Aslında, bu sınıf yalnızca Update() ve UpdateFast() metotlarının bir uygulanışını oluşturur, benzerdirler, tek fark ikincisinin çok daha hızlı olmasıdır. Bu metotlar her çubukta yeni emirler oluşturur ve eskilerini siler, böylece emir yaşam döngüsünü simüle edecek bir sonraki sınıf için veri hazırlar. Türler, açılış fiyatları, hacimler ve ileri çalışma için gereken diğer önemli parametreler dahil olmak üzere gerekli tüm emir parametreleri bu sınıfa atanır.

Bir sonraki sınıf, emir simülasyonu sürecinin yanı sıra, sinyallerin üretildiği temelde ticaret için gerekli parametrelerin hesaplamalarını uygular:

class Simulation:public PositionGenerator // then assemble a simulator of positions (inherited from the position generator)
   {// market parameter calculations will also performed in this class
   protected:
   double BuyPercent;// percent of open Buy positions
   double SellPercent;// percent of open Sell positions
   double StartVolume;// starting total volume of open Buy positions (the same for Buys and Sells)
   double RelativeVolume;// relative volume
   double SummVolumeBuy;// total volume for Buys
   double SummVolumeSell;// total volume for Sells
   
   public:   
   Simulation( ENUM_GRID_WEIGHT WeightStopLimitFillingType0
                     ,int HalfCorridorLimitStop0,int OrdersToOneBar0,int BarsTotal0
                     ,int ExpirationOpenLimit0,int ExpirationOpenStop0
                     ,int ExpirationClose0
                     ,int ProfitPointsCorridorPart0,int LossPointsCorridorPart0
                     ,double VolumeAlphaStop0,double VolumeAlphaLimit0,double VolumeAlphaMarket0) 
   :PositionGenerator(WeightStopLimitFillingType0
                     ,HalfCorridorLimitStop0,OrdersToOneBar0,BarsTotal0
                     ,ExpirationOpenLimit0,ExpirationOpenStop0
                     ,ExpirationClose0
                     ,ProfitPointsCorridorPart0,LossPointsCorridorPart0
                     ,VolumeAlphaStop0,VolumeAlphaLimit0,VolumeAlphaMarket0) 
      {
      CreateNewOrders();
      CalculateStartVolume();// calculate starting volumes
      UpdateVirtual();// first update virtual orders to process part of them as market orders in the next function
      UpdateMarket();// now update the state of all market orders
      CalculateCurrentVolume();// calculate current volumes of all open orders
      CalculatePercent();// calculate the percentage of positions
      CalculateRelativeVolume();// calculate relative volume
      }

   double GetBuyPercent()// get the percentage of open Buy deals
      {
      return BuyPercent;
      }
      
   double GetSellPercent()// get the percentage of open Sell deals
      {
      return SellPercent;
      }
      
   double GetRelativeVolume()// get relative volume
      {
      return RelativeVolume;
      }

   virtual void Update() override
      {
      PositionGenerator::Update();// call everything that was before
      UpdateVirtual();// first update virtual orders to process part of them as market orders in the next function
      UpdateMarket();// now update the state of all market orders
      CalculateCurrentVolume();// calculate current volumes of all open orders
      CalculatePercent();// calculate the percentage of positions
      CalculateRelativeVolume();// calculate relative volume
      }
      
   virtual void UpdateFast() override
      {
      PositionGenerator::UpdateFast();// call everything that was before
      UpdateVirtualFast();// first update virtual orders to process part of them as market orders in the next function
      UpdateMarketFast();// now update the state of all market orders
      CalculateCurrentVolume();// calculate current volumes of all open orders
      CalculatePercent();// calculate the percentage of positions
      CalculateRelativeVolume();// calculate relative volume
      }   
      
   private:
   
   void UpdateVirtual()// update the status of virtual orders
      {
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      int SizeBarOrders=ArraySize(BarOrders);
      
      if ( VolumeAlphaLimit != 0.0 )
         {
         for ( int i=SizeBarOrders; i>0; i-- )// update the state of limit orders simulating each candlestick
            {
            for ( int j=SizeBarOrders-1; j>i; j-- )// update the state of all candlesticks preceding this one
               {
               for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
                  {
                  if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_VIRTUAL 
                  && BarOrders[j].BuyLimitOrders[k].WantedPrice <= High[i] 
                  && BarOrders[j].BuyLimitOrders[k].WantedPrice >= Low[i] )// if the order is virtual and is inside a candlestick, then it turns into a market one
                     {
                     BarOrders[j].BuyLimitOrders[k].Status = STATUS_MARKET;
                     BarOrders[j].BuyLimitOrders[k].IndexMarket = i;
                     }
                  if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_VIRTUAL 
                  && BarOrders[j].SellLimitOrders[k].WantedPrice <= High[i] 
                  && BarOrders[j].SellLimitOrders[k].WantedPrice >= Low[i] )// the same
                     {
                     BarOrders[j].SellLimitOrders[k].Status = STATUS_MARKET;
                     BarOrders[j].SellLimitOrders[k].IndexMarket = i;
                     } 
                 
                  /////// Check for interest expiration of limit players
                  if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_VIRTUAL )//
                     {
                     if ( BarOrders[j].BuyLimitOrders[k].IndexMarket - 1 >= BarOrders[j].BuyLimitOrders[k].BarsExpirationOpen )
                     BarOrders[j].BuyLimitOrders[k].Status=STATUS_ABORTED;
                     else
                        {
                        if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                        BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart/double(BarOrders[j].BuyLimitOrders[k].BarsExpirationOpen);
                        if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                        }
                     }
                  if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_VIRTUAL )//
                     {
                     if ( BarOrders[j].SellLimitOrders[k].IndexMarket - 1 >= BarOrders[j].SellLimitOrders[k].BarsExpirationOpen  )
                     BarOrders[j].SellLimitOrders[k].Status=STATUS_ABORTED;
                     else
                        {
                        if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                        BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart/double(BarOrders[j].SellLimitOrders[k].BarsExpirationOpen);
                        if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;                  
                        }
                     } 
                  }
               }         
            }
         }
         
      if ( VolumeAlphaStop != 0.0 )
         {
         for ( int i=SizeBarOrders; i>0; i-- )// update the state of limit orders simulating each candlestick
            {
            for ( int j=SizeBarOrders-1; j>i; j-- )// update the state of all candlesticks preceding this one
               {
               for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
                  {
                  if ( BarOrders[j].SellStopOrders[k].Status == STATUS_VIRTUAL 
                  && BarOrders[j].SellStopOrders[k].WantedPrice <= High[i] 
                  && BarOrders[j].SellStopOrders[k].WantedPrice >= Low[i] )// the same
                     {
                     BarOrders[j].SellStopOrders[k].Status = STATUS_MARKET;
                     BarOrders[j].SellStopOrders[k].IndexMarket = i;
                     }
                  if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_VIRTUAL 
                  && BarOrders[j].BuyStopOrders[k].WantedPrice <= High[i] 
                  && BarOrders[j].BuyStopOrders[k].WantedPrice >= Low[i] )// the same
                     {
                     BarOrders[j].BuyStopOrders[k].Status = STATUS_MARKET;
                     BarOrders[j].BuyStopOrders[k].IndexMarket = i;
                     }
                  
                  /////// Check for interest expiration of stop and limit players
                  if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_VIRTUAL )//
                     {
                     if ( BarOrders[j].BuyStopOrders[k].IndexMarket - 1 >= BarOrders[j].BuyStopOrders[k].BarsExpirationOpen  )
                     BarOrders[j].BuyStopOrders[k].Status=STATUS_ABORTED;
                     else
                        {
                        if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                        BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart/double(BarOrders[j].BuyStopOrders[k].BarsExpirationOpen);
                        if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;                  
                        } 
                     }
                  if ( BarOrders[j].SellStopOrders[k].Status == STATUS_VIRTUAL )//
                     {
                     if ( BarOrders[j].SellStopOrders[k].IndexMarket - 1 >= BarOrders[j].SellStopOrders[k].BarsExpirationOpen  )
                     BarOrders[j].SellStopOrders[k].Status=STATUS_ABORTED;
                     else
                        {
                        if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                        BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart/double(BarOrders[j].SellStopOrders[k].BarsExpirationOpen);
                        if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;                     
                        }
                     }                                                                       
                  }
               }         
            }
         }               
      }
      
   void UpdateMarket()// update the status of market orders
      {
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      int SizeBarOrders=ArraySize(BarOrders);
      
      if ( VolumeAlphaLimit != 0.0 )
         {
         for ( int i=SizeBarOrders; i>1; i-- )// update the state of orders simulating each candlestick
            {
            for ( int j=SizeBarOrders-1; j>i; j-- )// update the state of all candlesticks preceding this one
               {
               for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
                  {
                  // Block for closing when prices change
                  if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                        {
                        BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].BuyLimitOrders[k].UpPriceToClose-BarOrders[j].BuyLimitOrders[k].WantedPrice);// with profit
                        BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].BuyLimitOrders[k].WantedPrice-BarOrders[j].BuyLimitOrders[k].LowPriceToClose);// with loss
                        }
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                     }
                  if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                        {
                        BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].SellLimitOrders[k].WantedPrice-BarOrders[j].SellLimitOrders[k].LowPriceToClose);//with profit
                        BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].SellLimitOrders[k].UpPriceToClose-BarOrders[j].SellLimitOrders[k].WantedPrice);//with loss
                        }
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;
                     } 
                  // End of lock for closing when prices change
               
                  // Block for closing when time changes******************************************************
                  if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart/double(BarOrders[j].BuyLimitOrders[k].BarsExpirationClose);
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                     }
                  if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart/double(BarOrders[j].SellLimitOrders[k].BarsExpirationClose);
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;
                     } 
                  }
               }         
            }
         }
         
      if ( VolumeAlphaStop != 0.0 )
         {
         for ( int i=SizeBarOrders; i>1; i-- )// update the state of orders simulating each candlestick
            {
            for ( int j=SizeBarOrders-1; j>i; j-- )// update the state of all candlesticks preceding this one
               {
               for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
                  {
                  // Block for closing when prices change
                  if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                        {
                        BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].BuyStopOrders[k].UpPriceToClose-BarOrders[j].BuyStopOrders[k].WantedPrice);// with profit
                        BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].BuyStopOrders[k].WantedPrice-BarOrders[j].BuyStopOrders[k].LowPriceToClose);// with loss
                        }
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;
                     }
                  if ( BarOrders[j].SellStopOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                        {
                        BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].SellStopOrders[k].WantedPrice-BarOrders[j].SellStopOrders[k].LowPriceToClose);//with profit
                        BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].SellStopOrders[k].UpPriceToClose-BarOrders[j].SellStopOrders[k].WantedPrice);//with loss
                        }
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;
                     }
               
                  // End of lock for closing when prices change
               
                  // Block for closing when time changes******************************************************
                  if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart/double(BarOrders[j].BuyStopOrders[k].BarsExpirationClose);
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;
                     }
                  if ( BarOrders[j].SellStopOrders[k].Status == STATUS_MARKET )//
                     {
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart/double(BarOrders[j].SellStopOrders[k].BarsExpirationClose);
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;
                     }
                  }
               }         
            }
         }
         
      if ( VolumeAlphaMarket != 0.0 )
         {
         for ( int i=SizeBarOrders; i>1; i-- )// update the state of orders simulating each candlestick
            {
            for ( int j=SizeBarOrders-1; j>i; j-- )// update the state of all candlesticks preceding this one
               {
               for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
                  {
                  // Block for closing when prices change
                  /// For obviously market positions
                  if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].BuyMarketOrders[k].UpPriceToClose-BarOrders[j].BuyMarketOrders[k].WantedPrice);// with profit
                     BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].BuyMarketOrders[k].WantedPrice-BarOrders[j].BuyMarketOrders[k].LowPriceToClose);// with loss
                     }
                  if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyMarketOrders[k].VolumeAlpha=0.0;
                              
                  if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart*(Open[i]-Low[i])/(BarOrders[j].SellMarketOrders[k].WantedPrice-BarOrders[j].SellMarketOrders[k].LowPriceToClose);// with profit
                     BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart*(High[i]-Open[i])/(BarOrders[j].SellMarketOrders[k].UpPriceToClose-BarOrders[j].SellMarketOrders[k].WantedPrice);// with loss
                     }
                  if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellMarketOrders[k].VolumeAlpha=0.0;                  
                  // End of lock for closing when prices change
               
                  // Block for closing when time changes******************************************************
              
                  /// For obviously market positions
                  if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart/double(BarOrders[j].BuyMarketOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyMarketOrders[k].VolumeAlpha=0.0;
                  if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart/double(BarOrders[j].SellMarketOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellMarketOrders[k].VolumeAlpha=0.0;               
                  //
                  }
               }         
            }
         }
      }
      
   /// fast methods****   
   void UpdateVirtualFast()// update the status of virtual orders
      {
      int SizeBarOrders=ArraySize(BarOrders);
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      
      if ( VolumeAlphaLimit != 0.0 )
         {
         for ( int j=SizeBarOrders-1; j>0; j-- )// update the state of all candlesticks preceding this one
            {
            for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
               {
               if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_VIRTUAL 
               && BarOrders[j].BuyLimitOrders[k].WantedPrice <= High[1] 
               && BarOrders[j].BuyLimitOrders[k].WantedPrice >= Low[1] )// if the order is virtual and is inside a candlestick, then it turns into a market one
                  {
                  BarOrders[j].BuyLimitOrders[k].Status = STATUS_MARKET;
                  BarOrders[j].BuyLimitOrders[k].IndexMarket = 1;
                  }
               if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_VIRTUAL 
               && BarOrders[j].SellLimitOrders[k].WantedPrice <= High[1] 
               && BarOrders[j].SellLimitOrders[k].WantedPrice >= Low[1] )// the same
                  {
                  BarOrders[j].SellLimitOrders[k].Status = STATUS_MARKET;
                  BarOrders[j].SellLimitOrders[k].IndexMarket = 1;
                  } 
                  
               /////// Check for interest expiration of limit players
               if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_VIRTUAL )//
                  {
                  if ( BarOrders[j].BuyLimitOrders[k].IndexMarket - 1 >= BarOrders[j].BuyLimitOrders[k].BarsExpirationOpen )
                  BarOrders[j].BuyLimitOrders[k].Status=STATUS_ABORTED;
                  else
                     {
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart/double(BarOrders[j].BuyLimitOrders[k].BarsExpirationOpen);
                     if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                     }
                  }
               if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_VIRTUAL )//
                  {
                  if ( BarOrders[j].SellLimitOrders[k].IndexMarket - 1 >= BarOrders[j].SellLimitOrders[k].BarsExpirationOpen  )
                  BarOrders[j].SellLimitOrders[k].Status=STATUS_ABORTED;
                  else
                     {
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart/double(BarOrders[j].SellLimitOrders[k].BarsExpirationOpen);
                     if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;                  
                     }
                  } 
               }
            }
         }
         
      if ( VolumeAlphaStop != 0.0 )
         {       
         for ( int j=SizeBarOrders-1; j>0; j-- )// update the state of all candlesticks preceding this one
            {
            for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
               {
               if ( BarOrders[j].SellStopOrders[k].Status == STATUS_VIRTUAL 
               && BarOrders[j].SellStopOrders[k].WantedPrice <= High[1] 
               && BarOrders[j].SellStopOrders[k].WantedPrice >= Low[1] )// the same
                  {
                  BarOrders[j].SellStopOrders[k].Status = STATUS_MARKET;
                  BarOrders[j].SellStopOrders[k].IndexMarket = 1;
                  }
               if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_VIRTUAL 
               && BarOrders[j].BuyStopOrders[k].WantedPrice <= High[1] 
               && BarOrders[j].BuyStopOrders[k].WantedPrice >= Low[1] )// the same
                  {
                  BarOrders[j].BuyStopOrders[k].Status = STATUS_MARKET;
                  BarOrders[j].BuyStopOrders[k].IndexMarket = 1;
                  }
                  
               /////// Check for interest expiration of stop players
               if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_VIRTUAL )//
                  {
                  if ( BarOrders[j].BuyStopOrders[k].IndexMarket - 1 >= BarOrders[j].BuyStopOrders[k].BarsExpirationOpen  )
                  BarOrders[j].BuyStopOrders[k].Status=STATUS_ABORTED;
                  else
                     {
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart/double(BarOrders[j].BuyStopOrders[k].BarsExpirationOpen);
                     if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;                  
                     } 
                  }
               if ( BarOrders[j].SellStopOrders[k].Status == STATUS_VIRTUAL )//
                  {
                  if ( BarOrders[j].SellStopOrders[k].IndexMarket - 1 >= BarOrders[j].SellStopOrders[k].BarsExpirationOpen  )
                  BarOrders[j].SellStopOrders[k].Status=STATUS_ABORTED;
                  else
                     {
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                     BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart/double(BarOrders[j].SellStopOrders[k].BarsExpirationOpen);
                     if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;                     
                     }
                  }                                                                       
               }
            }
         }         
      }
      
   void UpdateMarketFast()// update the status of market orders
      {
      int size=ArraySize(BarOrders[0].BuyLimitOrders);
      int SizeBarOrders=ArraySize(BarOrders);
      
      if ( VolumeAlphaLimit != 0.0 )
         {
         for ( int j=SizeBarOrders-1; j>0; j-- )// update the state of all candlesticks preceding this one
            {
            for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
               {
               // Block for closing when prices change
               if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].BuyLimitOrders[k].UpPriceToClose-BarOrders[j].BuyLimitOrders[k].WantedPrice);// with profit
                     BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].BuyLimitOrders[k].WantedPrice-BarOrders[j].BuyLimitOrders[k].LowPriceToClose);// with loss
                     }
                  if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                  }
               if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].SellLimitOrders[k].WantedPrice-BarOrders[j].SellLimitOrders[k].LowPriceToClose);// with profit
                     BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].SellLimitOrders[k].UpPriceToClose-BarOrders[j].SellLimitOrders[k].WantedPrice);// with loss
                     }
                  if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;
                  } 
               // End of lock for closing when prices change
               
               // Block for closing when time changes******************************************************
               if ( BarOrders[j].BuyLimitOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].BuyLimitOrders[k].VolumeAlpha-=BarOrders[j].BuyLimitOrders[k].VolumeStart/double(BarOrders[j].BuyLimitOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].BuyLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyLimitOrders[k].VolumeAlpha=0.0;
                  }
               if ( BarOrders[j].SellLimitOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].SellLimitOrders[k].VolumeAlpha-=BarOrders[j].SellLimitOrders[k].VolumeStart/double(BarOrders[j].SellLimitOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].SellLimitOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellLimitOrders[k].VolumeAlpha=0.0;
                  } 
               //
               }
            }
         }
         
      if ( VolumeAlphaStop != 0.0 )
         {
         for ( int j=SizeBarOrders-1; j>0; j-- )// update the state of all candlesticks preceding this one
            {
            for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
               {
               // Block for closing when prices change
               if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].BuyStopOrders[k].UpPriceToClose-BarOrders[j].BuyStopOrders[k].WantedPrice);// with profit
                     BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].BuyStopOrders[k].WantedPrice-BarOrders[j].BuyStopOrders[k].LowPriceToClose);// with loss
                     }
                  if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;
                  }
               if ( BarOrders[j].SellStopOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                     {
                     BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].SellStopOrders[k].WantedPrice-BarOrders[j].SellStopOrders[k].LowPriceToClose);// with profit
                     BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].SellStopOrders[k].UpPriceToClose-BarOrders[j].SellStopOrders[k].WantedPrice);// with loss
                     }
                  if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;
                  }
               
               // End of lock for closing when prices change
               
               // Block for closing when time changes******************************************************
               if ( BarOrders[j].BuyStopOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].BuyStopOrders[k].VolumeAlpha-=BarOrders[j].BuyStopOrders[k].VolumeStart/double(BarOrders[j].BuyStopOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].BuyStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyStopOrders[k].VolumeAlpha=0.0;
                  }
               if ( BarOrders[j].SellStopOrders[k].Status == STATUS_MARKET )//
                  {
                  if ( BarOrders[j].SellStopOrders[k].VolumeAlpha > 0.0 )
                  BarOrders[j].SellStopOrders[k].VolumeAlpha-=BarOrders[j].SellStopOrders[k].VolumeStart/double(BarOrders[j].SellStopOrders[k].BarsExpirationClose);
                  if ( BarOrders[j].SellStopOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellStopOrders[k].VolumeAlpha=0.0;
                  }
               //
               }
            }
         }
         
       if ( VolumeAlphaMarket != 0.0 )
         {
         for ( int j=SizeBarOrders-1; j>0; j-- )// update the state of all candlesticks preceding this one
            {
            for ( int k=0; k<size; k++ )// update the state inside each preceding candlestick
               {
               /// For obviously market positions
               if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha > 0.0 )
                  {
                  BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].BuyMarketOrders[k].UpPriceToClose-BarOrders[j].BuyMarketOrders[k].WantedPrice);// with profit
                  BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].BuyMarketOrders[k].WantedPrice-BarOrders[j].BuyMarketOrders[k].LowPriceToClose);// with loss
                  }
               if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyMarketOrders[k].VolumeAlpha=0.0;
                              
               if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha > 0.0 )
                  {
                  BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart*(Open[1]-Low[1])/(BarOrders[j].SellMarketOrders[k].WantedPrice-BarOrders[j].SellMarketOrders[k].LowPriceToClose);// with profit
                  BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart*(High[1]-Open[1])/(BarOrders[j].SellMarketOrders[k].UpPriceToClose-BarOrders[j].SellMarketOrders[k].WantedPrice);// with loss
                  }
               if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellMarketOrders[k].VolumeAlpha=0.0;                  
               // End of lock for closing when prices change
               
               // Block for closing when time changes******************************************************
             
               /// For obviously market positions
               if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha > 0.0 )
               BarOrders[j].BuyMarketOrders[k].VolumeAlpha-=BarOrders[j].BuyMarketOrders[k].VolumeStart/double(BarOrders[j].BuyMarketOrders[k].BarsExpirationClose);
               if ( BarOrders[j].BuyMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].BuyMarketOrders[k].VolumeAlpha=0.0;
               if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha > 0.0 )
               BarOrders[j].SellMarketOrders[k].VolumeAlpha-=BarOrders[j].SellMarketOrders[k].VolumeStart/double(BarOrders[j].SellMarketOrders[k].BarsExpirationClose);
               if ( BarOrders[j].SellMarketOrders[k].VolumeAlpha < 0.0 ) BarOrders[j].SellMarketOrders[k].VolumeAlpha=0.0;               
               //
               }
            }
         }                          
      }      
   ///******
      
   void CalculateStartVolume()// calculate the starting total volume of all positions (relative to it we will estimate market fullness)
      {
      StartVolume=0;
      int size=ArraySize(BarOrders[0].BuyStopOrders);
      if ( VolumeAlphaStop != 0.0 )
         {
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               StartVolume+=BarOrders[j].BuyStopOrders[i].VolumeStart;
               }
            }        
         }
         
      if ( VolumeAlphaLimit != 0.0 )
         {
         size=ArraySize(BarOrders[0].BuyLimitOrders);
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               StartVolume+=BarOrders[j].BuyLimitOrders[i].VolumeStart;
               }         
            }
         }
         
      if ( VolumeAlphaMarket != 0.0 )
         {
         size=ArraySize(BarOrders[0].BuyMarketOrders);
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               StartVolume+=BarOrders[j].BuyMarketOrders[i].VolumeStart;
               }         
            }
         }         
      }
      
   void CalculateCurrentVolume()// calculate the current total volume of all positions
      {
      SummVolumeBuy=0;
      SummVolumeSell=0;
      int size=ArraySize(BarOrders[0].BuyStopOrders);
      
      if ( VolumeAlphaStop != 0.0 )
         {
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               if ( BarOrders[j].BuyStopOrders[i].Status == STATUS_MARKET )
               SummVolumeBuy+=BarOrders[j].BuyStopOrders[i].VolumeAlpha;
               if ( BarOrders[j].SellStopOrders[i].Status == STATUS_MARKET )
               SummVolumeSell+=BarOrders[j].SellStopOrders[i].VolumeAlpha;            
               }         
            }
         }
      
      if ( VolumeAlphaLimit != 0.0 )
         {   
         size=ArraySize(BarOrders[0].BuyLimitOrders);
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               if ( BarOrders[j].BuyLimitOrders[i].Status == STATUS_MARKET )
               SummVolumeBuy+=BarOrders[j].BuyLimitOrders[i].VolumeAlpha;
               if ( BarOrders[j].SellLimitOrders[i].Status == STATUS_MARKET )
               SummVolumeSell+=BarOrders[j].SellLimitOrders[i].VolumeAlpha;            
               }         
            }
         }
      
      if ( VolumeAlphaMarket != 0.0 )
         {
         size=ArraySize(BarOrders[0].BuyMarketOrders);
         for ( int j=ArraySize(BarOrders)-1; j>=0; j-- )
            {
            for ( int i=0; i<size; i++ )
               {
               SummVolumeBuy+=BarOrders[j].BuyMarketOrders[i].VolumeAlpha;
               SummVolumeSell+=BarOrders[j].SellMarketOrders[i].VolumeAlpha;
               }         
            }
         }         
      }
      
   void CalculatePercent()// calculate the percentage of Buys and Sells relative to all positions
      {
      if ( (SummVolumeBuy+SummVolumeSell) != 0.0 ) BuyPercent=100.0*SummVolumeBuy/(SummVolumeBuy+SummVolumeSell);
      else BuyPercent=50;
      if ( (SummVolumeBuy+SummVolumeSell) != 0.0 ) SellPercent=100.0*SummVolumeSell/(SummVolumeBuy+SummVolumeSell);
      else SellPercent=50;
      }      
      
   void CalculateRelativeVolume()// calculate relative volumes of Buys and Sells (calculate only uncovered part of positions)
      {
      if ( SummVolumeBuy >= SummVolumeSell ) RelativeVolume=(SummVolumeBuy-SummVolumeSell)/StartVolume;
      else RelativeVolume=(SummVolumeSell-SummVolumeBuy)/StartVolume;
      }                   
   
   };

Kodun tamamı hem MetaTrader 4 hem de MetaTrader 5 için geçerlidir. Bu sınıflar her iki platformda da derlenebilir. Elbette MetaTrader 5'te, MQL4'te olduğu gibi önceden tanımlanmış dizileri önceden uygulamalısınız. Bu kodu burada vermeyeceğim. Ekteki kaynak kodundan kontrol edebilirsiniz. Kodum çok orijinal değil ama çalışıyor. Şimdi tek yapmamız gereken ticaretten sorumlu değişkenleri ve ilgili işlevselliği uygulamaktır. Her iki terminal için Uzman Danışmanlar aşağıya eklenmiştir.

Kod çok yoğun kaynak gerektirmektedir, bu yüzden analize başlamak için yavaş mantık uygulaması ve çubuklar üzerinde çalışmak için hızlı uygulama düzenledim. Tüm Uzman Danışmanlarım, yapay tik oluşturmaya ve her tik testinin diğer istenmeyen sonuçlarına bağımlılıktan kaçınmak için çubuklarla çalışır. Elbette, yavaş işlevlerden tamamen kaçınabiliriz. Ancak bu durumda başlangıç analizi söz konusu olmayacaktır. Dahası, sınıf gövdesi dışında işlevsellik uygulamaktan hoşlanmıyorum, çünkü bu bence resmin bütünlüğünü bozuyor.

Son sınıf yapıcısı, girdiler olacak aşağıdaki parametreleri kabul edecektir. İsterseniz, bu tür birçok simülasyon yapabilirsiniz, çünkü bu sadece bir sınıf örneğidir:

input bool bPrintE=false;// print market parameters
input CLOSE_MODE CloseModeE=CLOSE_FAST;// order closing mode
input WORK_MODE ModeE=MODE_SIMPLE;// simulation mode
input ENUM_GRID_WEIGHT WeightFillingE=WEIGHT_SAME;// weight distribution type
input double LimitVolumeE=0.5;// significance of limit orders
input double StopVolumeE=0.5;// significance of stop orders
input double MarketVolume=0.5;// significance of market orders
input int ExpirationBars=100;// bars for full expiration of open orders
input int ExpirationOpenStopBars=1000;// patience of a stop player in bars, after which the order is canceled
input int ExpirationOpenLimitBars=1000;// patience of a limit player in bars, after which the order is canceled
input int ProfitPointsCloseE=200;// points to close with profit
input int LossPointsCloseE=400;// points to close with loss
input int HalfCorridorE=500;// half-corridor for limit and stop orders
input int OrdersToOneBarE=50;// orders for half-grid per 1 bar
input int BarsE=250;// bars for analysis
input double MinPercentE=60;// minimum superiority of one trading side in percentage 
input double MaxPercentE=80;// maximum percentage
input double MinRelativeVolumeE=0.0001;// minimum market filling [0...1]
input double MaxRelativeVolumeE=1.00;// maximum market filling [0...1]

Her şey basit ve açık olduğu için burada ticaretle ilgili değişkenleri vermeyeceğim. 

İşte ticaretin uygulandığı fonksiyon:

void Trade()
   {
   if ( Area0 == NULL )
      {
      CalcAllMQL5Values();
      Area0 = new Simulation(WeightFillingE,HalfCorridorE,OrdersToOneBarE,BarsE
       ,ExpirationOpenLimitBars,ExpirationOpenStopBars,ExpirationBars,ProfitPointsCloseE,LossPointsCloseE
       ,StopVolumeE,LimitVolumeE,MarketVolume);      
      }
   
   switch(ModeE)
      {
      case MODE_SIMPLE:
         Area0.Update();// update simulation
      case MODE_FAST:
         Area0.UpdateFast();// fast update simulation
      }
   
   if (bPrintE)
      {
      Print("BuyPercent= ",Area0.GetBuyPercent());
      Print("SellPercent= ",Area0.GetSellPercent());
      Print("RelativeVolume= ",Area0.GetRelativeVolume());
      }
      
   if ( CloseModeE == CLOSE_FAST && Area0.GetBuyPercent() > 50.0 )
      {
      if ( !bInvert ) CloseBuyF();
      else CloseSellF();
      }
      
   if ( CloseModeE == CLOSE_FAST && Area0.GetSellPercent() > 50.0 )
      {
      if ( !bInvert ) CloseSellF();
      else CloseBuyF();
      }      
      
   if ( Area0.GetBuyPercent() > MinPercentE && Area0.GetBuyPercent() < MaxPercentE 
   && Area0.GetRelativeVolume() >= MinRelativeVolumeE && Area0.GetRelativeVolume() <= MaxRelativeVolumeE )
      {
      if ( !bInvert )
         {
         CloseBuyF();
         SellF();
         }
      else
         {
         CloseSellF();
         BuyF();
         }   
      }
      
   if ( Area0.GetSellPercent() > MinPercentE && Area0.GetSellPercent() < MaxPercentE 
   && Area0.GetRelativeVolume() >= MinRelativeVolumeE && Area0.GetRelativeVolume() <= MaxRelativeVolumeE )
      {
      if ( !bInvert )    
         {
         CloseSellF();
         BuyF();
         }  
      else
         {
         CloseBuyF();
         SellF();
         }
      }
   }

İstenirse, daha iyi ticaret koşulları ve daha karmaşık bir fonksiyon oluşturmak mümkündür, ancak şu ana kadar bunda bir anlam görmüyorum. Ben her zaman ticaret ile mantıksal kısmı birbirinden ayırmaya çalışırım. Mantık nesne içerisinde uygulanır. Simülasyon nesnesi ilk tetiklemede ticaret fonksiyonunda dinamik olarak oluşturulur; sonlandırma sırasında silinir. Bunun nedeni, MQL5'te önceden tanımlanmış dizilerin bulunmaması ve MQL4'e benzer sınıf çalışmasını sağlamak için yapay olarak oluşturulmaları gerektiğidir.


Çalışan ayarlar nasıl bulunur?

Deneyimlerime dayanarak, ayarları manuel olarak seçmenin daha iyi olduğunu söyleyebilirim. Ayrıca, düşük zaman dilimlerinde çalışan ve küçük matematiksel beklentiye sahip Uzman Danışmanlar için ilk aşamada makası göz ardı etmenizi öneririm - bu, başlangıçta performans işaretlerini kaçırmamanıza yardımcı olacaktır. MetaTrader 4 bu amaç için çok iyidir. Başarılı bir aramayı, nihai matematiksel beklentiyi ve kâr faktörünü (sinyal gücü) artırmak amacıyla her zaman revizyon, düzenleme ve benzeri işlemler takip eder. Ayrıca, girdi verilerinin yapısı, ideal olarak, bağımsız çalışma modlarına izin vermelidir. Başka bir deyişle, diğer ayarların değerine rağmen bir ayarın sistem performansı üzerinde en bağımsız etkiye sahip olması gerekir. Bu yaklaşım, bulunan tüm sinyalleri bir araya getirecek dengeli ayarlar yapılmasını sağlayarak genel sinyali iyileştirebilir. Böyle bir yaklaşım her zaman mümkün değildir, ancak bizim durumumuzda her emir türünü ayrı ayrı analiz ettiğimiz için uygulanabilir.


Uzman Danışmanı test etme

Bu Uzman Danışman herhangi bir hazırlık yapılmadan, sıfırdan yazılmıştır. Yani bu Uzman Danışman kodu benim için de yenidir. Buna benzer bir Uzman Danışmanım vardı ama çok daha basitti ve tamamen farklı bir mantığa sahipti. Bunu vurgulamak istiyorum, çünkü makalenin amacı, piyasa fiziğini tam olarak tanımlamasa bile, altında yatan bazı doğru temelleri olan herhangi bir fikrin bir miktar performans gösterme şansının çok yüksek olduğunu göstermektir. Sistem temel performans yeteneklerini gösteriyorsa, bunu test edebilir, bu sistemde neyin işe yaradığını bulabilir ve piyasa anlayışında bir sonraki seviyeye geçebiliriz. Bir sonraki seviye, kendi üreteceğiniz daha kaliteli Uzman Danışmanlardır.

Uzman Danışmanı test ederken, birkaç günümü sabırla ticaret parametrelerini seçmek için harcamak zorunda kaldım. Her şey sıkıcı ve uzundu ama çalışan ayarları bulmayı başardım. Elbette bu ayarlar çok zayıf ve simülasyon sadece 1 emir türü kullanılarak gerçekleştirildi, ancak bu bilerek yapıldı. Çünkü belirli bir emir türünün bir sinyali nasıl etkilediğini ayrı ayrı analiz etmek ve ardından diğer emir türlerini simüle etmeye çalışmak daha iyidir. İşte MetaTrader 4'teki sonucum:

EURUSD 2010.01.01-2020.11.01

İlk olarak MetaTrader 4 için bir sürüm oluşturdum ve mümkün olan en düşük makas ile test ettim. Gerçek şu ki, özellikle daha düşük zaman dilimlerinde modelleri aramak için her tiki görmemiz gerekiyor. MetaTrader 5 sürümünü test ederken, MetaTester 5'in kendi takdirine bağlı olarak ayarlayabileceği makaslar nedeniyle bunu göremiyoruz.

Bu, stres testi ve gerçek sistem performansını değerlendirmek için mükemmel bir araçtır. Sistemi gerçek tikler üzerinde test etmek için son aşamada kullanılmalıdır. Bizim durumumuzda, sistemi MetaTrader 4'te test etmeye başlamak daha iyidir. Herkese bu yaklaşımı kullanmalarını tavsiye ediyorum, çünkü hemen beşinci sürümde test etmeye başlarsanız, daha kaliteli ayarlar için temel oluşturabilecek birçok mükemmel ayar seçeneğini kaybedebilirsiniz.

Birçok nedenden dolayı optimizasyonun kullanılmasını önermiyorum, ancak ana neden parametrelerin basit bir yinelemesi olmasıdır. Parametreleri manuel olarak denemezseniz nasıl çalıştığını anlayamazsınız. Eski bir radyoyu alır, elektrik bağlar ve çalıştırırsanız, büyük olasılıkla bir radyo istasyonu bulamazsınız. Burada da aynı şey geçerlidir. Bir şey yakalamayı başarsanız bile, ne olduğunu anlamak zor olacaktır.

Bir diğer çok önemli husus ise emir sayısıdır. Çubuk sayısına göre ne kadar çok emir açılırsa, o kadar güçlü fizik bulunur ve gelecekte performansı konusunda endişelenmezsiniz. Ayrıca, bulunan modellerin makasın içinde yer alabileceğini ve bu anların kontrolsüz bırakılması durumunda sistemin işe yaramaz hale gelebileceğini unutmayın!

MetaTrader 5 sınayıcısına ihtiyacımız olan yer burası. MetaTrader 5, gerçek tikler kullanarak bir stratejiyi test etmeye izin verir. Ne yazık ki, gerçek tikler tüm döviz çiftleri ve enstrümanlar için nispeten yakın bir dönem için mevcuttur. Sistemin 2020'de çalışıp çalışmadığını görmek için MetaTrader 5 sürümünü gerçek tikler ve çok katı makas gereksinimleri kullanarak test edeceğim. Ama önce, sistemi daha önce kullanılan dönemde "Her tik" modunda test edeceğim:

Bu test modu, gerçek tiklerin kullanıldığı mod kadar iyi değildir. Ancak, ilk sonuçtaki sinyallerin sadece çok küçük bir kısmının burada kaldığı açıktır. Bununla birlikte, makası karşılayan ve hatta küçük bir kâr sağlayan sinyaller vardır. Ayrıca, sınayıcının derin geçmişten aldığı makaslardan emin değilim. Bu testte lot 0,01’di, bu da matematiksel beklentinin 5 puan olduğu anlamına geliyor, ki bu da grafik çok iyi görünmese de orijinal testten bile daha yüksek. Bu verilere hala güvenilebilir çünkü arkasında ilk testte 100.000 işlemden oluşan büyük bir örneklem var.

Şimdi de geçen yıla bir göz atalım:

Bu testte lotu 0,1 olarak belirledim, bu nedenle matematiksel beklenti 23,4 puan, bu da MetaTrader 4'teki ilk testin sadece 3 puan beklentiye sahip olduğu düşünüldüğünde oldukça iyi. Beklenti gelecekte düşebilir, ancak çok fazla puan düşmeyecektir. Yani breakeven bir ticaret için yine de yeterli olacaktır.

Her iki terminal için Uzman Danışman aşağıdaki ekte mevcuttur. Ayarları değiştirebilir ve limit ve piyasa emirleri için çalışan parametreler bulmaya çalışabilirsiniz. Ardından ayarları kombine edebilir ve bazı ortalama parametreler belirleyebilirsiniz. Ne yazık ki, bundan en iyi şekilde yararlanmak için yeterli zamanım olmadı, bu nedenle daha fazla manevra için yer var.

Elbette, bir grafik üzerinde başlatıp keyfini çıkarabileceğiniz, kullanıma hazır bir Uzman Danışman olmadığını lütfen unutmayın. Simülasyonu diğer emir türlerini kullanarak test edin ve ardından ayarları kombine edin ve Uzman Danışman güvenilir ticaret sonuçları gösterene kadar bu iki test döngüsünü tekrarlayın. Muhtemelen bazı filtreler ekleyebilir veya algoritmalarda düzenlemeler yapabilirsiniz. Testlerden de görülebileceği gibi, daha fazla iyileştirme mümkündür. Dolayısıyla ekteki programı kullanabilir ve istikrarlı sonuçlar elde etmek için onu geliştirebilirsiniz. Ayrıca, daha yüksek zaman dilimleri için uygun ayarları bulmayı başaramadım. Uzman Danışman en iyi M5'te çalışmaktadır, ancak belki başka zaman dilimleri de bulabilirsiniz. Ayrıca, ayar kümesinin diğer döviz çiftlerinde nasıl performans gösterdiğini kontrol etmek için zamanım olmadı. Bununla birlikte, genellikle bu tür düz çizgiler Uzman Danışmanın diğer döviz çiftlerinde de çalışması gerektiği anlamına gelir. Zamanım olursa Uzman Danışmanı geliştirmeye devam etmeye çalışacağım. Bu makaleyi yazarken, Uzman Danışmanda bazı kusurlar ve hatalar buldum, bu yüzden hala yapılacak çok şey var.


Sonuç

Simülatör, bu analiz yöntemine ilişkin iyi beklentileri kanıtladı. İlk sonuçları elde ettikten sonra, bunların nasıl iyileştirileceğini, algoritmanın nasıl modernize edileceğini ve daha iyi, daha hızlı ve daha değişken hale getirileceğini düşünmenin zamanı geldi. Bu yaklaşımın en büyük avantajı maksimum basitlikte olmasıdır. Sonuçta, mantığın uygulanmasıyla ilgili tüm karmaşıklıkları bir kenara bırakırsak, aslında bu yöntemin genel mantığı fiziksel açıdan çok basittir.

Fiyat hareketini etkileyen tüm faktörleri dikkate alamayız. Ancak böyle en az bir faktör olsa bile (bunu güvenilir bir şekilde tanımlayamasak bile), o zaman yanlış kod açıklaması bile belirli sinyaller üretecektir. Bu sinyaller çok yüksek kalitede olmayabilir, ancak bu fikirden bir miktar kâr elde etmek için oldukça yeterli olacaktır. İdeal bir formül bulmaya çalışmayın, bu imkansızdır, çünkü piyasayı etkileyen tüm faktörleri asla dikkate alamazsınız.

Üstelik tam olarak benim yaklaşımımı kullanmak zorunda da değilsiniz. Bu makalenin amacı, piyasayı en azından kısmen tanımlayan bazı piyasa fiziğini kullanmak ve fikri kanıtlayabilecek bir Uzman Danışman yazmaktı. Sonuç olarak, bu tür varsayımların çalışan bir sistem için temel oluşturabileceğini gösteren bir Uzman Danışman geliştirdim.

Ayrıca kodun küçük ve büyük kusurları ve hataları olduğu gerçeğini de göz önünde bulundurun. Bu haliyle bile Uzman Danışman çalışmaktadır. Sadece rafine etmelisiniz. Bir sonraki makalede, daha basit, daha etkili ve herkes tarafından bilinen başka bir çok varlıklı piyasa analizi türü sunacağım. Yine bir Uzman Danışman oluşturacağız.

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

Ekli dosyalar |
Simulation.zip (27.31 KB)
Ticaret için kombinatorik ve olasılık teorisi (Bölüm IV): Bernoulli mantığı Ticaret için kombinatorik ve olasılık teorisi (Bölüm IV): Bernoulli mantığı
Bu makalede, iyi bilinen Bernoulli şemasını vurgulamaya ve ticaretle ilgili veri dizilerini tanımlamak için nasıl kullanılabileceğini göstermeye karar verdim. Tüm bunlar daha sonra kendi kendini uyarlayan bir ticaret sistemi oluşturmak için kullanılacaktır. Ayrıca, özel bir durumu Bernoulli formülü olan daha genel bir algoritma arayacağız ve bunun için bir uygulama bulacağız.
Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 28): Geleceğe doğru (III) Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 28): Geleceğe doğru (III)
Emir sistemimizin hala yapamadığı bir görev var, ancak bunu nihayet çözeceğiz. MetaTrader 5, emir değerlerinin oluşturulmasına ve düzeltilmesine olanak tanıyan bir fiş sistemi sağlar. Fikir, aynı fiş sistemini daha hızlı ve daha verimli hale getirecek bir Uzman Danışmana sahip olmaktır.
Ticaret için kombinatorik ve olasılık teorisi (Bölüm V): Eğri analizi Ticaret için kombinatorik ve olasılık teorisi (Bölüm V): Eğri analizi
Bu makalede, çok durumlu sistemleri iki duruma indirgeme olasılığı ile ilgili bir çalışma yapmaya karar verdim. Makalenin temel amacı, olasılık teorisine dayalı ölçeklenebilir ticaret algoritmalarının daha da geliştirilmesine yardımcı olabilecek analizler yapmak ve faydalı sonuçlara varmaktır. Tabii ki bu konu matematik içeriyor. Ancak daha önceki makalelerden edindiğim tecrübeler ışığında, genel bilgilerin detaylardan daha faydalı olduğunu düşünüyorum.
Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 27): Geleceğe doğru (II) Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 27): Geleceğe doğru (II)
Doğrudan grafik üzerinde daha eksiksiz bir emir sistemine geçiş yapıyoruz. Bu makalede, emir sistemini düzeltmenin, daha doğrusu daha kolay anlaşılır hale getirmenin bir yolunu göreceğiz.