移動平均(およびその他の指標)と誤差の比較

 

みなさん、こんにちは。

SMAクロスをベースにしたEAを書いています(というか、簡単そうなのですでにやっているつもりでした)。でも...ある問題に直面しました。Expert Advisorは次の原則で動作します:新しいバーが表示されると、それは私がちょうど現れた最後のもの(最後とその前のもの)をカウントしない、最後の2つのバーのSMAを分析します。ここに 書かれているように、一見正しく値を比較しているように見えます。唯一の例外は、iMAが最後のパラメータ(バーでのオフセット)1および2でそれぞれ呼び出されることである。おおよそこのような感じです(引用元のコードを類推して書き直した場合)。

// берем два соседних значения Быстрой МА
double fast0=iMA(Symbol(), Period(), 10, 0, MODE_SMA, PRICE_CLOSE, 1);
double fast1=iMA(Symbol(), Period(), 10, 0, MODE_SMA, PRICE_CLOSE, 2);
 
// берем два значения Медленной МА
double slow0=iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 1);
double slow1=iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 2);
 
// сравниваем значения и определяем направление пересечения
if (fast0>slow0 && fast1<slow1) Print("Пересечение ВВЕРХ");
if (fast0<slow0 && fast1>slow1) Print("Пересечение ВНИЗ");

エキスパートアドバイザーは、前のトレードを閉じる - 新しいものを開くの原則に交差信号の存在下で原始的な形で機能します。もちろん、すべてのクロスオーバーが検出されれば、取引は常に次々と実行されます(売り-買い-売り-買い-・・・)。つまり、Expert Advisorは、常に1つのオープントレードしか持っていません(最初のトレードを開始する前の瞬間は除く)。そこで、問題の核心は...。分タイムフレームとSMA期間5と34のために 17.02.2015で01:24のバーで戦略テスターで閉じる 私は興味深い状況をキャッチしました。このような特徴を持つムービングは、バークローズで直接クロスするのが特徴です。これがその写真です。

17.02.2015 01:24

デバッグのために、出力しています。与えられたコードと比較したログの対応関係は以下の通りです。

SMAFastCurrent =fast0

SMASlowCurrent =slow0

SMAFastPrevious =fast1

SMASlowPrevious=slow1 および

SMACurDifference = SMAFastCurrent - SMASlowCurrent

SMAPrevDifference = SMAFastPrevious - SMASlowPreviousc (つまり、fast0,slow0fast1,slow1 のそれぞれの差).

ですから、これらの違いが符号に変わると、ムービングクロッシングの信号であることを意味します。しかし、この例では、more or lessのチェックが効きません。これらの差分の値は、ログに表示されます。赤い四角は、問題の次のバー(1時25分)の差分値、オレンジはその次のバー(1時26分)の差分値を示しています。そして、前のバーのSMACurDifferenceと現在のバーのSMAPrevDifferenceの値が等しくなければならないことは明らかです(現在のバーが前のバーとなり、新しいバーがその場所となるのです)。つまり、1時24分の問題バーの終値でムービングクロスが発生しているので、次のバー(1時25分)ではSMAFastCurrentとSMASlowCurrentの値は(およそ)等しくなっています。デバッガは、それらを概ね5桁以内の値で表示します(SMAFastCurrent = 1.13371 SMASlowCurrent = 1.13371 図参照)。その差は無限大ですが、0ではありません(SMACurDifference = 2.220446049250313e-016)。次のバーでは、同じ正確な値での差がちょうどゼロになります(赤のSMACurDifferenceとオレンジのSMAPrevDifferenceを比べてみてください)。しかし、一見同じように見える値でも違うのであれば、その誤差をどのように解消すればよいのか、実はよくわからないのです。それゆえ、2つの質問があります。

1.同じミュービングでも、隣接する2つの小節が交互に現れる瞬間にカウントされるだけで、なぜ違う結果になるのでしょうか?

2.ゼロとの比較ではなく、何らかのイプシロンを導入して、それとの比較をしようと考えていました。しかし、通常、無限小と0を比較するために行われます。この無限小の符号変化を求めたい場合はどうでしょうか。

もちろん、隣接する3本のバーを分析することはできますが、その終値の価格では、ムービング同士が限りなく近い距離で接触することが理論的に可能なのです。そのような事態はめったに起こらないとは思いますが(特に時間軸を大きくとると)、それでも起こる可能性はあります。そして、それは何らかの形で捕捉されるべきであり、ムーバンの交差はこの場合にも検出されるべきなのです。

よろしくお願いします。

Навигатор по форуму и ответы на часто задаваемые вопросы. Настоятельно Рекомендуется к Прочтению! - MQL4 форум
  • www.mql5.com
Навигатор по форуму и ответы на часто задаваемые вопросы. Настоятельно Рекомендуется к Прочтению! - MQL4 форум
 

正規化・比較をしてみてください。

MQL4リファレンスマニュアル(MQL5も同じ)には、「Real Types (double, float)」で 開くと書いてあります。

"...2つの実数を互いに等しいかどうか比較することはできない。一見同じように見える2つの数字が、小数点以下15桁の差で不等号になる場合がほとんどです。2つの実数を正しく比較するには、それらの数値の正規化された差とゼロ値を比較しなければ ならない......。"

"...2つの実数を等しいかどうか比較することは、そのような比較が正しくないため、強く推奨されない。


しかし、2つの実数を等しく比較する必要がある場合、2つの異なる方法で行うことができる。最初の方法は、2つの数値の差を、比較の精度を定義する何らかの小さな値で比較する方法である。


2つ目の方法は、2つの実数の差を正規化したものをゼロ値で比較する方法である。正規化された数値の差をゼロと比較しても意味がない。正規化された数値を用いた数学的演算は、正規化されていない結果をもたらすからである。

...."

 
rosomah:

正規化・比較をしてみてください。

MQL4リファレンスマニュアル(MQL5も同じ)には、「Real Types (double, float)」で 開くと書いてあります。

"...2つの実数を互いに等しいかどうか比較することはできない。一見同じように見える2つの数字が、小数点以下15桁の差で不等号になる場合がほとんどです。2つの実数を正しく比較するには、それらの数値の正規化された差をゼロの値と比較 する必要があります...。"

"2つの実数を等しいかどうか比較することは、この比較が有効でないため、断固としてお勧めしません


しかし、2つの実数を等しく比較する必要がある場合、2つの異なる方法で行うことができる。最初の方法は、2つの数値の差を、比較の精度を定義する何らかの小さな値で比較する方法である。


第二の方法は、二つの実数の差を正規化したものをゼロと比較する方法である。正規化された数値の差をゼロと比較しても意味がない。正規化された数値を用いた数学的演算は、正規化されていない結果をもたらすからである。

...."

実数を比較しての平等は不可能であることは十分承知しています。引用したコードには、等号の比較はありません。そして、それにも必要性はない。ここで必要なのは、0になるかもしれない無限小の符号の変化をキャッチすることです。この場合も、すべてを単純に0と比較するのは危険です。そして、ノーマライゼーションは、ここでさらに危険なものになる...。MA の初期値は未知の数値に正規化されています(時間枠が小さいほど、MA の値も小さくなります)。小数点以下一桁に正規化すると、MAの値がすべて0になる場合があります。正直なところ、2つのMA値の差がどうなるのか、よくわからないのですが...。

 

gammaray:

実数を対等に比較することは不可能であることは十分承知しています。引用したコードでは、等号の比較はしていません。そして、それにも必要性はない。この場合、0に近い符号の変化を捉える必要があります。この場合も、すべてを単純に0と比較するのは危険です。そして、ノーマライゼーションは、ここでさらに危険なものになる...。MA の初期値は未知の数値に正規化されています(時間枠が小さいほど、MA の値も小さくなります)。小数点以下一桁に正規化すると、MAの値がすべて0になる場合があります。正直なところ、2つのMA値の違いがどうなるのかよくわからないのですが......。

なぜノーマライゼーションはより危険なのか?

だから

...

もし、2つの実数が等しいかどうかを比較する必要がある場合、2つの異なる方法で比較 することができます。最初の方法は、2つの数値の差を、比較の精度を設定する何らかの小さな値で比較する方法である。

...

2つ目は、2つの実数の差を正規化したものをゼロと比較する方法である。正規化された数値の差をゼロと比較しても意味がありません。正規化された数値を使った数学的演算は、正規化されていない結果になるからです。

bool CompareDoubles(double number1,double number2)
  {
   if(NormalizeDouble(number1-number2,8)==0) return(true);
   else return(false);
  }
void OnStart()
  {
   double d_val=0.3;
   float  f_val=0.3;
   if(CompareDoubles(d_val,f_val)) Print(d_val,"equals",f_val);
   else Print("Different: d_val = ",DoubleToString(d_val,16),
              "  f_val = ",DoubleToString(f_val,16));
// Результат: Different: d_val= 0.3000000000000000   f_val= 0.3000000119209290
  }
  • また、私の個人的な実務経験(控えめに言っても、数値の2重 比較を適用し、その比較に基づいて発動する条件の正しさという点で、プログラムの動作を入念にチェックした回数という点では決して少なくありませんし、今も適用しています)からも、そのことは明らかです。
そのため、このような比較は脅威でないだけでなく、考えることができるのです。
if(NormalizeDouble(number1-number2,dig)==0)
if(NormalizeDouble(number1-number2,dig)>0)
if(NormalizeDouble(number1-number2,dig)<0)

// dig=Digits();

が、逆に、2つの 方法の うちの1つのバリエーションで、ドキュメンテーションにあるように、2倍の 数の比較に適用することが できる。

以来

2つの実数が 互いに等しいかどうかを比較することはできません。一見同じように見える2つの数字が、小数点以下15桁の値の違いで不等号になる場合がほとんどである。2つの実数を正しく比較するためには、これらの数値の正規化された差を0と比較する必要があります。



追記:たまたま、ドキュメンテーションにあった最初の方法は、自分にとって使いにくいものでした。その結果、私は最初の方法の経験があまりないのです。

しかし、2番目の方法(つまり、条件演算子の式でゼロ値を持つ2つの実数の正規化された差を比較 する)を使用すると、問題は発生しませんでした。

しかし、正規化されていない数値の比較を行った場合(ここでは、最初の方法を使用せずに 行った場合を含む)、そうです、double 型の数値の比較に基づいて条件の不正なトリガーを発見したことがありました。

 
gammaray:

これらは、ドキュメンテーションに あるフレーズです。

2つ目の方法は、2つの実数の差を正規化したものをゼロと比較する方法である。 正規化された数値の差をゼロと比較しても意味がありません。なぜなら、正規化された数値を使った数学的演算は、正規化されていない結果をもたらすからです。

私としては、単純化して言えば、数学の演算(様々な変換を含む)において、このようなことをしてはいけないと認識しています。

// dig=Digits();

double delta=NormalizeDouble(number1-number2,dig);

if (delta>0)


すなわち、上記の前回の 記事では、2つの実数の正規化された差を0とした場合の比較の 例を挙げました。そして、この投稿では、正規化した数値の差をゼロと 比較しています(Documentationの上のフレーズの文章を理解した上で)。

簡単に言えば、そんなところです。

 

gammaray:

...

2つのMA値の差を正規化することで、何ができるのか、正直なところよくわからない

追伸:この点については、とりあえずPrint()を入れてみて、大量のデータで何が出力されるかを確認するとよいでしょう。印刷では、数学的な操作から得られた非正規化および正規化(実験を行う図表より大きいものを含む、いくつかの小数点以下まで)された値を印刷します。数学的な演算に基づいて形成されているため、単純に非正規化および正規化されたiMA値も含む。

念のため、double型の非正規化値、正規化値を印刷する場合は、もちろんDoubleToStringで 数値からテキスト値に追加変換することも明記しておきます(DoubleToStringでは小数点以下の桁数を実験してください)。

 
gammaray:

追記:MQL4プログラマー向けに書かれたスキームの例では、数学的計算値の正規化が規定されていない、あるいは明示されていない場合があると思いますので、補足します。

  • どのような条件下でも、その方式を理解しやすくするため。
  • 常に、及び/又は、どこでも正規化が必要なわけではない(タスクによって異なる許容誤差のレベル、及び、それに応じて、いくつかの個々のタスクの小数点以下の桁数に関する数学的演算の結果の異なるさらなる正規化(又はその欠如)を適用することを想定することを含む)。
  • また、開発者が質問を明確にするために、ドキュメントを 読んでいることが前提となっています。
こんな感じ。
 
より正確です。
// сравниваем значения и определяем направление пересечения
if (fast0>slow0 && fast1<=slow1) Print("Пересечение ВВЕРХ");
if (fast0<slow0 && fast1>=slow1) Print("Пересечение ВНИЗ");

つまり、Ma値が等しくなる可能性も考慮されていなかったのです。

сравнивать вещественные числа на равенство нельзя

が少し違う。
 
Aleksey Lebedev:
他のことについても少し。

何のために、どのようなタスク/オブジェクトを考えているかによります。

だから、このスレッドの書き込みを書くにあたって、根拠としているのは

  • 最初の投稿にあるスクリーンショットと質問です。
  • このスレッドの筆者の2番目の投稿(正常化の危険性について)。

と、それに伴い、ここから、簡潔に言えば、上記の私の書き込みの意味です。

正規化により、比較(および/または出力値)の精度の要求レベルや、特定のタスクや目標に対する許容誤差を設定/調整することができ、これにより、コードで特定の条件を規定したときに意図したとおりにプログラム条件をトリガすることができます。また、正規化した差分をゼロと比較することで、関係演算による比較だけでなく、調整・調節を行うことができる。"==".


追伸:このように、どんな場合でも、ここに挙げた2つの方法のうち、 最初の方法による実数の比較は、どんな小さな値の数の差の比較でも、比較のレベルを調整する必要がある場合には、正規化の適用よりも悪いとは言えない ことを、もう一度明記しなければならない(私にとっては、第2の方法がより便利に見え、最初の方法は、実際の適用にとってより詳細だとは思わなかった こともあるのだが...)。


 

これは原理的にmqlとは関係ない。抽象的なプログラミング言語を例にとろう。私が示したこの特定の例では、主な問題は、1つの同じバーのミューウイングの差の値が等しくないことです(最初の計算では2e-16、2番目の計算では正確に0です)。この場合、この交差点はどのように決定されてもよい。mqlに戻ると、正規化とは、数値を丸める(というより、シシ関数のfloorのように、ある符号以降の数値を単純に全部落として、ある小数点以下の桁数にする)ことを意味します。では、どの桁に正規化すればいいのか、どうすればいいのか。間違った桁を選択した場合、すべての値は常に正確に0に丸められる可能性があります。ですから、ここで正常化することは危険であり、一般的には問題を解決することはできません。

アレクセイ・レベデフが書いたことについては。はい、この方向で考えていました。しかし、両者の差を0以上で比較すると、誤信号が出る確率がある(例えば、隣り合うバー間のミュービングが全く同じ値である場合など、理論的にはあり得ること)。その場合、両者の差は符号を変えずに(クロスオーバーは発生しない)、クロスオーバーのための信号がプログラム的に決定されることになる。ご指摘の通り、more or equalに1つだけ比較を載せることも可能です。しかし、問題は、この状況での計算では、まず0(2e-16)に等しくなく、次のバーでは正確に0になるが、厳密な比較になることです。

同じ差を異なるバーで計算すると、同じ結果にならない理由を理解することが重要である。もし結果が同じであれば、非厳格な比較を1つ導入することで、常に問題は解決されます

 

gammaray:

しかし、そうすると問題は、この状況での計算はまず0(2e-16)にはならず、次のバーではすでに正確に0になっているのですが、厳密な比較が行われます。

同じ差を異なるバーで計算すると、同じ結果にならない理由を理解することが重要である。もし結果が同じであれば、非厳格な比較を1つ導入することで、常に問題は解決されます

iMA関数の計算が最適化されている可能性が高いです。最初の値=sum(close)/N、2番目=MAの前の値+(新しいclose-古いclose)/N。