エラー、バグ、質問 - ページ 741

 
ivandurak:

私は説明するのが苦手なんです。もう一回やらせてください。タスクは、各通貨が独自のパラメータを持つ、通貨のポートフォリオを形成することです。最適化されたポートフォリオでは、通貨は参加しないかもしれません。6つの通貨を各通貨ごとに21の最適化ステップで計算し、合計が億単位になるようにしました。

さて、問題です。もし、ある通貨があるフラグで取引することを禁じているならば、そのパラメータを最適化する意味はない。とにかく、そのパラメータは結果に何ら影響を与えないが、オプティマイザは結果に影響を与えないパラメータを適合させようとすることになる。私のように、あなたができないことは分かっていますが、希望はまだ生きています。

はい、わかりました、不要なパスが発生します。

TCが許すなら、各ペアを別々に最適化すべきです。

一般的な最適化には、マジックヘッジの罠にはまるイミがあります ))) 。

私が提案した方法とは別の方向ですが、無駄な走行を減らすという解決策もあります。

例えば、パラメータ100を50~150の区間で列挙した場合。

これにより、選択肢は1次元分少なくなります。

input bool trpar2=true; // вЫключен флажок
input int grusdchf=100; // включен флажок перебора 49-150
input int grusdjpy=100; // включен флажок перебора 50-150

if (grusdchf==49)  // если 49 то запрет торговли
  {
   x_trpar2=false;
  }
 else              // иначе берет установленное значение флага и параметров
  {
   x_trpar2=trpar2;
  }

// далее по коду для запрета используем x_trpar2
 
ivandurak:

私は説明するのが苦手なんです。もう一回やらせてください。タスクは、各通貨が独自のパラメータを持つ、通貨のポートフォリオを形成することです。最適化されたポートフォリオでは、通貨は参加しないかもしれません。6つの通貨を各通貨ごとに21の最適化ステップで計算し、合計が億単位になるようにしました。

さて、問題です。もし、ある通貨があるフラグで取引することを禁じているならば、そのパラメータを最適化する意味はない。とにかく、そのパラメータは結果に何ら影響を与えないが、オプティマイザは結果に影響を与えないパラメータをあてはめようとしているのだ。私のように、無理だとわかっていても、希望はまだくすぶっているのです。

各ペアのInit()とTrade()のようなものがあれば、パラメータは既に決まっているので、あとは株を決めるだけで、タスクは解決します。しかし、残念ながら、一般論として、システムの任意の数のために - 解決することはできません。

そこで、ステップ「システムの分数」を指定する必要があります。6系統の場合は、f-eyeでパス数を算出します。

int PartCount6(double _mult) {
   int __= (int)(1.0 / _mult) + 1;
   int x, y, z, t, t1, t2, count = 0;
   for (t = 0; t < __; ++t) for (x = 0; x < __; ++x) 
      for (y = 0; y < __; ++y) for (z = 0; z < __; ++z) 
         for (t1 = 0; t1 < __; ++t1) for (t2 = 0; t2 < __; ++t2) 
            if (x + y + z + t + t1 + t2 == __- 1) ++count;
   return(count);     
}

そのためのスクリプトを作ることは可能である。

input double Mult = 0.04;

void OnStart() {
   Alert(PartCount6(Mult));
}

さらに、最適化されたタスクは、Mult(最適化されていない)とpartの2つのパラメータを持ち、1〜PartCount6(Mult)まで1刻みで設定されています。

input double Mult  = 0.04;
input int    part = 3276;

CZ1 gbp;
CZ2 jpy;
CZ3 eursek, eur;
CZ4 audcad, sek;

int x, y, z, t, t1, t2; 

int OnInit() {
   int __= (int)(1.0 / Mult) + 1;
   int count = 0;
   for (x = 0; x < __; ++x) {
      for (y = 0; y < __; ++y) {
         for (z = 0; z < __; ++z) {
            for (t = 0; t < __; ++t) {
               for (t1 = 0; t < __; ++t1) {
                  for (t2 = 0; t2 <__; ++t2) { 
                     if (x + y + z + t + t1 + t2 == __- 1) {
                        ++count;
                        if (count == part) break; // Вот где goto был бы полезен, или break n
                     }
                  }
                  if (count == part) break;
               }
               if (count == part) break; 
            }
            if (count == part) break;
         }
         if (count == part) break;
      }
      if (count == part) break;
   }
   if (x) gbp.Init(..);//его доля - x * Mult, т. е., нужно в Init долю передавать как параметр
   if (y) jpy.Init(..); 
   if (z) eur.Init(..);
   if (t) eursek.Init(..);
   if (t1) audcad.Init(..);
   if (t2) sek.Init(...);
}

void OnTick() {
   if (x) gbp.Trade();
   if (y) jpy.Trade();
   if (z) eur.Trade();
   if (t) eursek.Trade();
   if (t1) audcad.Trade();
   if (t2) sek.Init(Trade);
}

ただ、ステップを小さくすればするほど、ループのステップ数が増えていくことに留意してください。例えば、パス回数を計算するスクリプトが5分以上の値を返さない場合は、ステップを減らした方が良いと思います。ステップを減らしたくない場合は、例えば通貨を半分に分け、グループごとにプロオプティマイズし、「グループとして」一緒に戻ってください。(あるいは、システムの相関関係を利用して、ペアで最適化するのがよいでしょう。そうすれば、サイクルはそれほど悪くありませんが、それはまた別の話です)。

他のシステム数(さらに少ない数、さらに多い数)でも、すべては同じです。

 

最適化の後、分数を知る必要があるので、最適なシングルパスを実行し、それをOnDeinitに記述します。

void OnDeinit(const int reason) {
  Print("x:", x * Mult, "; y:", y * Mult, "; z:", z * Mult, "; t:", t * Mult, "; t1:", t1 * Mult, "; t2:", t2 * Mult);
}
 

このバグは1年前に発見してテストし、フォーラムで言及したこともあります。

結論から言うと、それはまだ生きています。

結論:コンストラクタで仮想関数が 呼び出されると、ネイティブ関数の代わりに祖先関数が呼び出されます。

class COracleTemplate
  {
private:
public:
   string            ClassName;
                     COracleTemplate(){Init();};
                    ~COracleTemplate(){DeInit();};
   virtual void      Init(){ClassName=this.Name();Print("loadSettings from ",ClassName);};
   virtual void      DeInit(){Print("saveSettings to ",ClassName);};
   virtual string    Name(){return("Prpototype");};
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CCO2:public COracleTemplate
  {
   virtual string    Name(){return("CO2");};
  };
class CH2O:public COracleTemplate
  {
   virtual string    Name(){return("H2O");};
  };
COracleTemplate* CO2,*H2O;
void OnStart()
  {
   CO2=new CCO2;
   CO2.Init();
   Print(CO2.Name()," ClassName=",CO2.ClassName);
   delete CO2;
   
   H2O=new CH2O;
//   H2O.Init();
   Print(H2O.Name()," ClassName=",H2O.ClassName);
   delete H2O;
  }

印刷物

2012.05.18 14:13:48     VirtualTest (EURUSD,M15)        saveSettings to Prpototype
2012.05.18 14:13:48     VirtualTest (EURUSD,M15)        H2O ClassName=Prpototype
2012.05.18 14:13:48     VirtualTest (EURUSD,M15)        loadSettings from Prpototype
2012.05.18 14:13:48     VirtualTest (EURUSD,M15)        saveSettings to CO2
2012.05.18 14:13:48     VirtualTest (EURUSD,M15)        CO2 ClassName=CO2
2012.05.18 14:13:48     VirtualTest (EURUSD,M15)        loadSettings from CO2
2012.05.18 14:13:48     VirtualTest (EURUSD,M15)        loadSettings from Prpototype

もし、これがバグであれば、修正をお願いします。

機能であれば、ヘルプで詳しく取り上げ、どのようなメリットがあるのかを説明する。

必要悪であれば、ヘルプの専用欄に記載してください。

そうでなければ、プログラムのバグを探すのに狂奔することはないでしょう。

ファイル:
 

祖先のコンストラクタは、その子孫とその仮想関数について 何も知りません。

オブジェクトはどのように構築されるのか?

1.まず、「原動機」のコンストラクタが呼び出される。その仮想関数テーブルを公開する。先祖は継承階層に続く子孫のことを何も知らないし、子孫の仮想関数テーブルもまだ存在しない。

2.階層内の次の子孫のコンストラクタが呼び出されます。この子孫は、その仮想関数テーブルを公開する。子孫の関数(仮想関数も含む)は、子孫で利用可能です。しかし、やはりこの子孫は、(ポイント1のように)階層的に続く子孫のことは何も知らないのです。

3.ポイント2を繰り返し、階層を満たすまで続けます。

概要コンストラクタで仮想関数を使用しないでください。また、デストラクタにも使用しないでください。

 
MetaDriver:

やむを得ない悪の場合は、ヘルプの専用欄にその旨を記載してください。

コンストラクタの前やデストラクタの起動後に仮想関数を 呼び出さないのが一般的なやり方です。
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
  • www.mql5.com
Основы языка / Объектно-ориентированное программирование / Виртуальные функции - Документация по MQL5
 
stringo:

祖先のコンストラクタは、その子孫とその仮想関数について 何も知りません。

オブジェクトはどのように構築されるのか?

1.まず、「原動機」のコンストラクタが呼び出される。その仮想関数テーブルを公開する。先祖は継承階層に続く子孫のことを何も知らないし、子孫の仮想関数テーブルもまだ存在しない。

2.階層内の次の子孫のコンストラクタが呼び出されます。この子孫は、それ自身の仮想関数テーブルを公開する。子孫の関数(仮想関数も含む)は、子孫で利用可能です。しかし、やはりこの子孫は、(ポイント1のように)階層的に続く子孫のことは何も知らないのです。

3.階層を満たすまで、2.を繰り返す。

概要コンストラクタで仮想関数を使用しないでください。デストラクタでもありません。

OK、でもやっぱり目立つところに置いてね、こんな感じなら。

一般的には、アセンブリの階層の問題ではなく、コンストラクタのどの位置にVMTを追加するかということです。 もし、最初に(ユーザが書いたコードの前に)追加されていれば、この問題は存在しないように思えますし、後続のコードはすでに仮想関数を呼び出しているかもしれません。 それは不可能ですか、好ましくないですか、それとも...??

TheXpert です。
コンストラクタの終了前とデストラクタの開始後に仮想関数を 呼び出さないのが一般的なやり方です。

他のオブジェクト指向言語の経験があっても、そんなことは知りませんでした。 コンストラクタの内部で仮想コールをする必要がないことが多いからでしょうか。

 
MetaDriver:

でも、ヘルプデスクの目立つところに置いておいてください。


ドキュメントには、この事実がいくつかの箇所で反映されます。
 
stringo:
ドキュメントには、この事実がいくつかの箇所に反映されます。

OK、素晴らしい。

Slavaさん、(一般的な開発のために)なぜコンストラクタの最初(祖先の初期化後)に仮想メソッドテーブルを初期化できないのか聞いていいですか?

--

場合によっては、コンストラクタで仮想コールを使用するコードは非常に便利です。最近の例では、コンストラクタでファイルからオブジェクトをロードする場合、仮想関数が 返す型IDと比較してロード中に型をチェックする計画でした。これは、コンストラクタからの仮想呼び出しが不可能なため、残念な結果になってしまいました。問題は解決したが、計画ほどエレガントではなかった。

Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
Документация по MQL5: Основы языка / Объектно-ориентированное программирование / Виртуальные функции
  • www.mql5.com
Основы языка / Объектно-ориентированное программирование / Виртуальные функции - Документация по MQL5
 
MetaDriver:
だから工場を作れ。問題は解決される。