Fiyat != Fiyat ? - sayfa 5

 

Fiyatların eşitliğiyle ilgili bu temel önermeyle başladım (daha doğrusu sadece çiftlerin eşitliği) -

(P1). y = 1.50000 varsayarsak: x == y, x'in (i) 1.499995'e eşit veya bundan büyük ve (ii) 1.500005'ten küçük herhangi bir gerçek sayı olduğu sürece.

P1'i temel alarak şu sonuca vardım -

(P2). y = 1.50000 varsayarsak: a == y, b == y ve a == b, yeter ki a ve b (i) 1.499995'e eşit veya ondan büyük ve (ii) 1.500005'ten küçük gerçek sayılardır.

Örnekler şunları içerir: 1.500055 == 1.50006, 1.500055 == 1.500064, 1.500051 != 1.500059 ve 1.500054 != 1.500056.

Yukarıdakileri kullanarak, (1) argüman olarak iki fiyatı alan, (2) bu fiyatları en yakın nokta eşdeğerine yuvarlayan ve (3) bu iki fiyatın eşit olup olmadığını belirleyen bir fonksiyon yarattım (aşağıda).

 bool IsEqual( double price1, double price2) {
   // Price Conditioning
   //    * this fixes the occurrence of 1.5000551 != 1.5000550
   price1 += Point * 0.0015 ;
   price2 += Point * 0.0015 ;
      
   int p1 = MathRound (price1 / Point ),
       p2 = MathRound (price2 / Point );
          
   return (p1 == p2);
}

Bu fonksiyon basit ve yalındır, ancak "Fiyat Koşullandırma" kısmı hakkında biraz yorum yapmalıyım. Çoğumuzun bildiği gibi, çiftler (yani, çift duyarlıklı kayan nokta biçimi değişkenleri) zaman zaman biraz belirsizdir ve ara sıra yuvarlama sorunlarına sahiptir. 1.5000551 ve 1.5000550'yi en yakın noktaya yuvarladığımda ve sonucu karşılaştırdığımda (sırasıyla 1.50006 ve 1.50005), yukarıdaki P1 ve P2 altında eşit olmalarına rağmen eşit olmadıklarını gördüm. (Birkaç test yaptıktan sonra) 1.5000550 değişmezinin ~1.5000549999 olarak değişkende saklandığı sonucuna vardım. Bunu düzeltmek için, fiyat yarı noktadan (x.xxxxx5) bir noktanın on binde 15'i içindeyse, fiyatın en yakın noktaya yuvarlamak için minimum eşiği karşıladığını varsaymaya karar verdim. Buna göre, en yakın noktaya yuvarlamadan önce her fiyata bir puanın on binde 15'ini ekliyorum. Şu anda, bu eklemenin istenmeyen sonuçlar olduğuna inanmıyorum. Ayrıca, bu değerler en yakın noktaya yuvarlama varsayımını artırmak/azaltmak için ayarlanabilir.

RaptorUK ve WHRoeder (ve diğerleri): Yukarıdakileri bir plan olarak kullanarak, RaptorUK'un önceki gönderisine dayanan ComparePrices() adlı aşağıdaki işlevi oluşturdum:

 #define EQ       1
#define NEQ     2
#define LT       3
#define LToE     4
#define GT       5
#define GToE     6

bool ComparePrices( double FristPrice, double SecondPrice, int ComparisonType) {
   // Price Conditioning
   FirstPrice  += Point * 0.0015 ;
   SecondPrice += Point * 0.0015 ;
      
   int price1 = MathRound (FirstPrice / Point ),
       price2 = MathRound (SecondPrice / Point );
                
   switch (ComparisonType) {
       case LToE: return (price1 < price2 || price1 == price2);
       case GToE: return (price1 > price2 || price1 == price2);
       case LT:   return (price1 < price2);
       case GT:   return (price1 > price2);
       case EQ:   return (price1 == price2);
       case NEQ:   return (price1 != price2);
       default :   return ( false );
   }    
}

Her zaman olduğu gibi, öğretici/yapıcı yorumlara açığız. :)

 

Bununla kendim biraz oynadım - kabul edilebilir bir okunabilirlik ve performans uzlaşmasına ulaşmaya çalışıyorum.


eq(a,b), ne(a,b), lt(a,b) vb. bireysel fonksiyonlara karar verdim.


Örneğin

 if (eq(a,b)) { ...}


4999999 yineleme için yavaş VM'mdeki performansla ilgili olarak, temel ölçümleri takip ediyorum:

Boş döngü: 370ms

satır içi MathAbs(ab) < gHalfPoint (genel): 2482ms

Boş bool Fonksiyon: 4266ms <-- Bu rakama mümkün olduğunca yaklaşmayı hedefliyorum.

Yönettiğim en hızlı eq() uygulaması aşağıdadır.

Bunlar, satır içi MathsAbs() çağrısından yaklaşık 2,3 kat ve boş bir boole işlevi çağrısından 1,3 kat daha yavaştır.

Ayrıca MQL'nin boolean ifadelerde kısa devre yapmadığını keşfettim.

 bool eq( double a, double b) {

   if (a > b) {
       return ((a-b) < gpoint2);
   } else {
       return ((b-a) < gpoint2);
   }

}

5558 ms'de

Veya statiği globallere tercih ediyorsanız (tüm kodu tek bir yerde tutmak için):

 bool eq( double a, double b) {
   static double p2= 0 ;
   if (p2== 0 ) p2 = Point / 2 ;
   
   if (a > b) {
       return (a-b < p2);
   } else {
       return (b-a < p2);
   }
}

5718 ms'de


lt(), gt() vb. daha hızlı olmalıdır çünkü eq() ve ne() daha karmaşıktır.

 
RaptorUK : Peki TestValue'un 1.57373 değil > veya < 'a eşit olmasını nasıl sağlayabilirim?

yapmazsın. kayan nokta, bazı sayılar için ASLA kesin değildir.

https://en.wikipedia.org/wiki/Floating_point

Kayan noktalı sayılar rasyonel sayılardır çünkü bir tam sayının diğerine bölünmesiyle gösterilebilirler. Örneğin 1.45×10 3 , (145/100)*1000 veya 145000/100'dür. Ancak taban, temsil edilebilecek kesirleri belirler. Örneğin, 1/5 bir ikili taban kullanılarak tam olarak bir kayan noktalı sayı olarak temsil edilemez, ancak tam olarak bir ondalık taban (0.2 veya 2×10 -1 ) kullanılarak temsil edilebilir. Bununla birlikte, 1/3 tam olarak ne ikili (0,010101...) ne de ondalık (0.333....) ile temsil edilemez, ancak taban 3'te önemsizdir (0.1 veya 1×3 -1 ).
Bu yüzden ASLA, ASLA NormalizeDouble kullanmayın diyorum. Bu bir Kludge. Kullanımı HER ZAMAN yanlıştır.
 
Thirteen :

 case LToE: return (price1 < price2 || price1 == price2);
case GToE: return (price1 > price2 || price1 == price2);

Aracının çifte değeri 1.2345750000000000 ile 1.2345849999999999999 arasında olabilir ve yine de aynı 1.23458 fiyat olarak kabul edilir.

Yine de işleviniz 1.2345750000000000000'in 1.2345849999999999999 GToE OLMADIĞINI söylüyor

Yine de işleviniz 1.2345849999999999999'un 1.2345750000000000000 LToE OLMADIĞINI söylüyor

Karşılaştırmalarda bir nokta/2 kullanmalısınız https://www.mql5.com/en/forum/136997/page3#780837

 
ydrol :

Bununla kendim biraz oynadım - kabul edilebilir bir okunabilirlik ve performans uzlaşmasına ulaşmaya çalışıyorum.

0.0'ın özel bir durum olduğuna inanıyorum, bu nedenle doğrudan 0.0 ile test edebilirsiniz.
 
WHRoeder :

Aracının çifte değeri 1.2345750000000000 ile 1.2345849999999999999 arasında olabilir ve yine de aynı 1.23458 fiyat olarak kabul edilir.

genel olarak katılıyorum Yukarıdaki mesajımda P1 ve P2'ye bakın.

WHRoeder :

Yine de işleviniz 1.2345750000000000000'in 1.2345849999999999999 GToE OLMADIĞINI söylüyor

Yine de işleviniz 1.2345849999999999999'un 1.2345750000000000000 LToE OLMADIĞINI söylüyor

Sorun, MT4/MQL'nin değişkenlerde kayan nokta değerlerini nasıl sakladığından kaynaklanmaktadır. Örneğin:

 double p1 = 1.234575000000000000 , p2 = 1.23458499999999999 ;
Print ( "p1 = " , DoubleToStr(p1, 8 ), " p2 = " , DoubleToStr(p2, 8 ));

günlük/günlükteki iki değişkeni yazdırır:

KarşılaştırmaFiyatları testi #1

Gördüğünüz gibi, p2 artık 1.2345849999999999 değil, bunun yerine 1.23458500 olur - inanıyorum ki, yuvarlama nedeniyle. İşlevimin p1'in p2'ye GToE olmadığını söylemesinin nedeni budur; ve aşağıdaki kodda görebileceğiniz gibi, kodunuz da aynı şeyi önerir - yani, p1'in GToE'den p2'ye olmadığı ve p1'in p2'ye Eşit Değil olduğu.

 double p1 = 1.234575000000000000 , p2 = 1.23458499999999999 ;
Print ( "p1 = " , DoubleToStr(p1, 8 ), " p2 = " , DoubleToStr(p2, 8 ));
Print ( "GToE: " , p1 >= p2);
Print ( "ComparePrices() for GToE: " , ComparePrices(p1, p2, GToE));
Print ( "WHRoeder GToE: " , p1 - p2 > - Point / 2 .);
Print ( "WHRoeder NEQ: " , MathAbs (p1 - p2) > Point / 2 .);

KarşılaştırFiyatlar testi #2

Karşılaştırmalarda bir nokta/2 kullanmalısınız

Nokta/2'nin maksimum sapma için çok küçük olma olasılığı vardır. Örneğin:

 double p1 = 1.234575000000000000 , p2 = 1.23458499999999999 , p3 = 1.234580 ;
Print ( "p1 = " , DoubleToStr(p1, 8 ), " p2 = " , DoubleToStr(p2, 8 ), " p3 = " , DoubleToStr(p3, 8 ));
Print ( "#1 WHRoeder NEQ: " , MathAbs ( 1.234575000000000000 - 1.23458499999999999 ) > Point / 2 .);
Print ( "#2 WHRoeder NEQ: " , MathAbs (p1 - p3) > Point / 2 .);
Print ( "#3 WHRoeder NEQ: " , MathAbs (p2 - p3) > Point / 2 .);

KarşılaştırFiyatlar testi #3

Varsayım, 1,234575'in 1,234580'e eşit olduğuysa, neden #2 NEQ'yu gösteriyor? Ayrıca, 1.23458'in komisyoncudan 1.234575000000000000 ila 1.2345849999999999999 arasında bir fiyat anlamına gelebilecek bir fiyat olduğunu varsayarsak, neden #1 NEQ göstersin? Aynı fiyat noktasını paylaşıyorlarsa eşit olmaları gerekmez mi (dolayısıyla yukarıdaki mesajımdaki Önerme 2'm)?

 

@Onüç,


Kodunuzda, kayan nokta hatalarından kaynaklanan kasıtsız yuvarlama hatalarına değil, uygulama mantığı nedeniyle kasıtlı yuvarlama farklılıklarına bakıyorsunuz, dolayısıyla fark:

İki tür "yuvarlama" şunlardır:

a) IEEE formatındaki ikili kesirlerden kaynaklanan içsel yuvarlama hataları . - bu sayıların tam olarak aynı olması amaçlanmıştır, ancak ondalık kesirlerin ikili gösterimi nedeniyle değildir. Ondalık sayıların MQ4 gösterimi ile yuvarlanırlar.

b) Bazı sayı veya ondalık basamaklara açık yuvarlama. (örneğin, Yazdırma veya bir Broker'a fiyatları gönderirken). - bunlar gerçekten aynı değerler anlamına gelmez, bunun yerine birinin rahatlığı için uygulama mantığı tarafından yuvarlanırlar.

Bu gerçekten bir hata değil. Yalnızca kayan nokta gösteriminden kaynaklanan hataların bu kadar büyük olması olası değildir (bir dizi kötü hesaplanmadıkça). Ancak kendi mantığınıza göre uygulamanızda bu tür bir karşılaştırma yapmak isteyebilirsiniz.


Gerçek yuvarlama hataları[a] genellikle çok küçüktür (Noktadan daha küçük büyüklük dereceleri) ve kasıtsızdır . Uygulama, çift veri türünü kullanarak bu sayıları tam olarak amaçlanan değer olacak şekilde yuvarlayamaz.

Açık yuvarlama farklılıkları[b] kasıtlıdır ve çok daha büyüktür (+/- 0,5 puan). (bu durumda). bu nedenle, uygulama mantığınız tarafından aynı puan değerine yuvarlanan iki sayı, başlangıçta neredeyse bir tam nokta olabilir.


İdeal olarak, önce [b] sayılarını yuvarlardım (yalnızca yuvarlama gerekliyse) ve sonra onları [a] karşılaştırırdım, bu noktada double sınırlamaları nedeniyle hata çok küçüktür. (örn. < 0.0000001)

Ancak kodunuz, yuvarlamadan önce karşılaştırmak içindir, bu durumda çok daha büyük olası farklılıklarla ayrıntılandırmanız gerekir. Ancak yuvarlama her zaman gerekli değildir. Sadece komisyoncuya fiyat gönderirken kullanırdım.


Başka bir şekilde düşünün (Eğer MQ4, Ondalık kesirlerin tam olarak temsil edilmesini sağlayan İkili Kodlu Ondalık kullansaydı - o zaman Fiyat ile ilgili tüm sorunlar != Fiyat ile ilgili tüm sorunlar ortadan kalkardı,

ancak yine de belirli işlemler için uygulamanızdaki sayıları en yakın noktaya yuvarlamanız ve karşılaştırmanız gerekir. (Esas olarak OrderXXX işlevleri)


>> "1.23458'in komisyoncudan 1.234575000000000000 ile 1.2345849999999999999 arasında bir fiyat anlamına gelebilecek bir fiyat olduğunu varsayarsak"

Burada yanılmış olabilirim (komisyoncuların nasıl çalıştığından emin değilim) ama bence komisyoncudan 1.23458 bir fiyat tam olarak budur. özellikle 100.000$'lık Lot boyutları ve dikkate alınması gereken daha büyükleri ile. Aksi takdirde, yayınlanan fiyatlardaki farktan yararlanarak (broker tarafından) çok para kazanılacaktır.

Anladığım kadarıyla, başvurunuz boyunca değil, yalnızca Broker'a gönderirken yuvarlamanız gerekiyor. Bu durumda küçük hatalar için karşılaştırmalar yeterli olacaktır.

Kayan nokta hatası, komisyoncu fiyatlarının yuvarlanmasından ayrıdır. Ancak ikisiyle de aynı anda ilgilenmek istiyorsanız, sanırım bu kişisel tercihtir (yine de kafa karıştırıcı olabilir mi?)

 

İşte tam sürümüm (umarım hata yoktur).

Bu 6 işlev sağlar:

eq(a,b) =
ne(a,b) !=
gt(a,b) >
lt(a,b) <
ge(a,b) >=
le(a,b) <=

if (ge(Bid,target)) sell sell sell...


Mantıklı olan, kodu okunabilir (IMO) tutmak ve çok fazla performans isabeti olmadan yazım hataları olasılığını azaltmaktır.

Tüm amaç ve amaçlar için bu işlevler, MQ4 kullanıcı işlevleri kullanılarak yapılabilecek kadar hızlı olmalıdır,

(Performans ve MathAbs(ab) için < HalfPoint bkz. https://www.mql5.com/en/forum/136997/page5#822505 gerçek bir EA'da olsa da (bir kıyaslamanın aksine) farkın önemsiz olduğundan şüpheleniyorum.


 bool gt( double a, double b) {
   static double p2= 0 ;
   if (p2== 0 ) p2 = Point / 2 ;
   
   if (a < b) {
       return ( false );
   } else {
       return (a-b > p2);
   }
}
bool lt( double a, double b) {
   static double p2= 0 ;
   if (p2== 0 ) p2 = Point / 2 ;
   
   if (a > b) {
       return ( false );
   } else {
       return (b-a > p2);
   }
}
bool ge( double a, double b) {
   static double p2= 0 ;
   if (p2== 0 ) p2 = Point / 2 ;
   
   if (a >= b) {
       return ( true );
   } else {
       return (b-a <= p2);
   }
}
bool le( double a, double b) {
   static double p2= 0 ;
   if (p2== 0 ) p2 = Point / 2 ;
   
   if (a <= b) {
       return ( true );
   } else {
       return (a-b <= p2);
   }
}
bool eq( double a, double b) {
   static double p2= 0 ;
   if (p2== 0 ) p2 = Point / 2 ;
   
   if (a > b) {
       return (a-b <= p2);
   } else {
       return (b-a <= p2);
   }
}

bool ne( double a, double b) {
   static double p2= 0 ;
   if (p2== 0 ) p2 = Point / 2 ;
   
   if (a > b) {
       return ((a-b) > p2);
   } else {
       return ((b-a) > p2);
   }
}
 
ydrol :

İşte tam sürümüm (umarım hata yoktur).

...

 bool eq( double a, double b) {
   static double p2= 0 ;
   if (p2== 0 ) p2 = Point / 2 ;
   
   if (a > b) {
       return (a-b <= p2);
   } else {
       return (b-a <= p2);
   }
}

Sıklıkla alıntılanan öncül:

  • Aracının çifte değeri 1.2345750000000000 ile 1.2345849999999999999 arasında olabilir ve yine de aynı 1.23458 fiyat olarak kabul edilir.

Bu öncülü göz önünde bulundurarak ve kodunuzu arka plan olarak kullanarak, bana neden (a) 1.234576 ve 1.234584'ün eşit olmadığı , (b) 1.234577 ve 1.234583'ün eşit olmadığı kabul edildiğini , ancak (c) söylediğinizi açıklayabilir misiniz? 1.234578 ve 1.234582 eşit kabul edilir mi? Örnek (b) neden (ve nasıl) örnek (c)'den daha az eşittir?

Yukarıda belirttiğim gibi, tüm bu fiyatların eşit olduğunu düşünüyorum çünkü her biri aynı fiyat noktasını - yani 1.23458'i paylaşıyor. Bu örnek, Nokta/2'nin maksimum sapma için çok küçük olabileceğine neden inandığımı (ve yukarıda söylediğimi) açıklıyor.

 

@Onüç, gözlemlerinize cevabım, https://www.mql5.com/en/forum/136997/page5#822672 bağlantısının üstündeki 3 gönderiyle aynı kalıyor. Benim bakış açımı anlamada ampul anına yol açabilecek kısmı tekrar edeceğim: (biraz gözden geçirme ve vurgu eklenerek)

Think of it another way (If MQ4 had used Binary Coded Decimal - which allows exact representation of Decimal fractions - then most of the original issues regarding Price != Price would go away, (and is often used on financial platforms for that very reason )

ancak yine de belirli işlemler için uygulamanızdaki sayıları en yakın noktaya yuvarlamanız ve karşılaştırmanız gerekir. (Esas olarak OrderXXX işlevleri)


Bu sadece kodunuzu nasıl yazdığınıza bağlıdır ve uygulama yuvarlaması arasında ayrım yapmak istiyorsanız (iki farklı sayının basitlik/kolaylık için kavramsal olarak/mantıksal olarak aynı olduğu kabul edilir),

ve kayan nokta hataları. Doğru ve yanlış yok ama bence bir yaklaşım diğerinden daha kafa karıştırıcı....


Ek olarak, kişisel olarak, yine önceki gönderide bahsedilen, alıntılanmayan (ama düzeltmeye açık!) öncül konusunda biraz şüpheliyim.