記事「多通貨エキスパートアドバイザーの開発(第17回):実際の取引に向けたさらなる準備」についてのディスカッション

 

新しい記事「多通貨エキスパートアドバイザーの開発(第17回):実際の取引に向けたさらなる準備」はパブリッシュされました:

現在、EAはデータベースを利用して、取引戦略の各インスタンスの初期化文字列を取得しています。しかし、データベースは非常に大容量であり、実際のEAの動作には不要な情報も多数含まれています。そこで、データベースへの接続を必須とせずにEAを機能させる方法を考えてみましょう。

以前の記事では、リアル口座での運用に向けたEAの改良について取り上げました。これまでは主に、ストラテジーテスター上で満足できる結果を得ることに注力してきましたが、実際の取引環境では、さらに多くの準備が必要です。

端末の再起動後にEAの動作を復元すること、取引銘柄の名称が多少異なる場合にも対応すること、指定した指標に到達した際に自動的に取引を終了することなどに加えて、次の課題にも直面しています。それは、取引戦略インスタンスおよびそのグループの最適化結果を格納したデータベースから、初期化文字列を直接取得している点です。

EAを起動するには、共有端末フォルダにデータベースファイルを配置する必要があります。しかし、データベースのサイズはすでに数ギガバイトに達しており、今後さらに拡大すると見込まれます。このため、データベースをEAに不可欠な構成要素とするのは現実的ではありません。実際に必要なのは、データベースに格納された情報のごく一部に過ぎないのです。したがって、EA内で必要な情報のみを抽出・利用できる仕組みを実装する必要があります。

Разрабатываеммультивалютныйсоветник(Часть17):Дальнейзаяподготовкакреальнойторговле 


作者: Yuriy Bykov

 

Yuri こんにちは!あなたのコードを勉強しているのですが、少し理解できません...。SimpleVolumesStrategy.mqhのコンストラクタにパラメータがあります:

         // 最小タイムフレームに新しいバーイベントハンドラを登録する。
         IsNewBar(m_symbol, PERIOD_M1);

なぜこのようなことをするのですか?なぜ、このストラテジー・インスタンスが起動される期間を、現在の期間ではなく、正確にM1とするのですか?この場合、Expert Advisor は指定した TF のバーオープンではなく、単純に M1 で動作すると理解しています。それとも何か間違って理解しているのでしょうか?

2つ目のポイントは、SignalForOpen()関数です:

      // 現在の音量が設定レベルを超えている場合
      if(m_volumes[0] > avrVolume * (1 + m_signalDeviation + m_ordersTotal * m_signaAddlDeviation)) {
         // もしローソク足の始値が現在値(終値)より小さければ、次のようになります。
         if(iOpen(m_symbol, m_timeframe, 0) < iClose(m_symbol, m_timeframe, 0)) {
            signal = 1; // 買いシグナル
         } else {
            signal = -1; // そうでなければ売りシグナル
         }
      }

バー0(現在)が計算で示されていますが、バー1(最後にクローズしたバー)があるはずです。最初のティックのバー0(始値で 計算する場合)にはボディがないため、始値は常に終値と等しくなります。そして、それはまだ形成されていないので、ボリュームを持つことはできません。何か誤解しているのかもしれないが、何となく動いている。なぜこうなるのか、理解したい。

また、このストラテジーに何らかのパラメータ(new)を投入したい場合、SimpleVolumesStage1.mq5 Expert Advisorの設定でパラメータを作成し、そこで文字列変数に渡す必要があるのですが、このクラス(SimpleVolumesStrategy.mqh)のコンストラクタで正しい順序でパースすればいいのでしょうか?それとも、他のどこかで規定する必要があるのでしょうか?

 

こんにちは、ビクター。

Зачем Вы это делаете? Почему именно период М1, а не текущий на котором запускается этот экземпляр стратегии? Как я понимаю в этом случае советник будет работать не по открытиям баров заданного ТФ а просто по м1. Или я что-то не правильно понимаю?

Expert Advisor の作業は、仮想ポジションのオープンと、オープンした仮想ポジションと実際のポジションの同期の 2 つの部分で構成されます。設定されたTFは、オープンシグナルを決定するために最初の部分でのみ使用されます。そして、仮想ポジションはいつでもTPまたはSLに達する可能性があるため、同期化は理想的には毎ティック、または少なくとも最小タイムフレームM1の新しいバーごとに実行されるべきです。

VirtualAdvisor::Tick()メソッドでは、M1を含むすべての監視シンボルとタイムフレームで新しいバーが発生したかどうかを最初にチェックします。新しいバーが発生していない場合、Expert Advisor はそれ以上のアクションを実行しません。M1 で新しいバーが発生したときのみ、他の動作を行います。この場合、M1上のOHLCモードで最適化しても、EAがチャート(すべてのティックがある)上で動作するときとほぼ同じ結果を得ることができます。そして、最適化はこの方法ではるかに速くなります。あなたが挙げたコードの行は、ストラテジーでM1の新しいバーを追跡する必要がない場合のセーフティネットにすぎません。こうすることで、少なくとも1つのシンボル上では追跡されることが保証される。

必要であれば、useOnlyNewBars_ = false という変数を使って、このモードを無効にすることもできます。そうすれば、Expert Advisorは利用可能なティックごとにポジションをチェックし、同期します。

ただ、最初のティックのバー0(始値で 動作する場合)にはボディがないため、始値は常に終値と等しくなります。そして、それはまだ形成されていないので、ボリュームを持つことはできません。私は何かを誤解しているかもしれませんが、何とか動作します...

新しいM1バーのオープンは、より高いタイムフレームのバーの内部で発生する可能性があります。SignalForOpen() は現在のタイムフレーム(通常は H1、M30、M15)を使用する ことに注意してください。したがって、現在のタイムフレームの始値と終値が一致することはありません。さらに、このチェックは、現在のタイムフレーム上の現在のバーのティックボリュームが、1バーの標準的なティックボリュームを大幅に超えた場合にのみ行われます。ティックボリュームが1しかない最初のティックでは、このようなことは起こりえません。

また、このストラテジーに何らかのパラメータ(new)を投入したい場合、設定のSimpleVolumesStage1.mq5 Expert Advisorでパラメータを作成し、そこで文字列変数に渡す必要があります。それとも、どこか他の場所に明記しなければならないのでしょうか?

もちろんです。

 
Yuriy Bykov #:

Expert Advisor の作業は、仮想ポジションのオープンと、オープンした仮想ポジションと実際のポジションの同期の 2 つの部分から構成される。設定されたTFは、オープンシグナルを決定するために最初の部分でのみ使用されます。また、仮想ポジションがTPまたはSLに到達する可能性があるため、同期化は各ティックまたは少なくとも最小タイムフレームM1の各新バーで実行されることが理想的です。

VirtualAdvisor::Tick()メソッドでは、M1を含むすべての監視シンボルとタイムフレームで新しいバーが発生したかどうかを最初にチェックします。新しいバーが発生していない場合、Expert Advisor はそれ以上のアクションを実行しません。M1 で新しいバーが発生したときのみ、他の動作を行います。この場合、M1上のOHLCモードで最適化しても、EAがチャート(すべてのティックが存在する)上で動作するときとほぼ同じ結果を得ることができます。そして、最適化はこの方法ではるかに速くなります。あなたが挙げたコードの行は、ストラテジーでM1の新しいバーを追跡する必要がない場合のセーフティネットにすぎません。こうすることで、少なくとも1つのシンボルで追跡されることが保証されます。

必要であれば、useOnlyNewBars_ = false という変数を使って、このモードを無効にすることもできます。そうすれば、Expert Advisorは利用可能なティックごとにポジションをチェックし、同期する。

なるほど。しかし、例えば、ポジションの同期をすべてのティックで動作させ、ストラテジーで指定したTF(m15,m30,h1)で新しいバーが発生したときに仮想(新規)ポジションのオープンが発生するようにすることはできますか?

Yuriy Bykov#:
新しいM1バーのオープンは、より高いタイムフレームのバーの内部で発生する可能性があります。SignalForOpen()は、通常H1、M30またはM15である現在のタイムフレームを使用する ことに注意してください。したがって、現在のタイムフレームの始値と終値が一致することはありません。さらに、このチェックは、現在のタイムフレーム上の現在のバーのティックボリュームが、1バーの標準的なティックボリュームを大幅に超えた場合にのみ行われます。ティックボリュームが1しかない最初のティックでは、このようなことは起こりえません。

少し理解できません。はい、SignalForOpen()は現在の仮想ストラテジーインスタンスの設定で設定されたTFを使用します。しかし、例えば、EAをクローズした最後のバーに対して厳密に動作させたい場合、ここではゼロの代わりに単位を指定する必要があります。

      if(m_volumes[0] > avrVolume * (1 + m_signalDeviation + m_ordersTotal * m_signaAddlDeviation)) {
         // もしローソク足の始値が現在値(終値)より小さければ、次のようになります。
         if(iOpen(m_symbol, m_timeframe, 0) < iClose(m_symbol, m_timeframe, 0)) {

ゼロの代わりに単位を指定すべきですか?私は正しく理解していますか?

 
Viktor Kudriavtsev #:
例えば、ストラテジーで指定したTF(m15,m30,h1)で新しいバーが発生したときに仮想(新規)ポジションのオープンが発生するように、ポジション同期を毎ティックで動作させることはできますか?

はい、これはuseOnlyNewBars_ = false の 場合です。この変数はストラテジーでは使用されず、ストラテジー自身が、いつ始値シグナルをチェックし、いつ始値シグナルを受信したらポジションを建てるかを決定します。例えば、H1 で新しいバーが発生したときのみ。この場合、バーの途中で受信したシグナルが次のバーの開始まで存続するようにコードを修正する必要があります。これで、受信したシグナルはすぐに使用され(仮想ポジションのオープンにつながる)、どこにも保存されなくなります。

ここが少し理解できません。はい、SignalForOpen()は、バーチャルストラテジーの現在のインスタンスの設定で設定されたTFを使用します。しかし、例えば、EAをクローズした最後のバーに対して厳密に動作させたい場合、ここで ゼロの代わりに単位を指定すべきでしょうか?私の理解は正しいでしょうか?

EA worked strictly on closed last bars"という言葉が、ティックボリュームが現在のバーで、 オープンのシグナルの方向を決定するためのしきい値を超えたときに、前のバーを取ってその方向を見るという意味であれば、あなたはすべてを正しく理解しています。

 

Yuri こんにちは。Expert Advisor SimpleVolumesStage3.mq5を実行し、データベースに情報を保存する際にエラーが発生しました:

2024.09.11 21:02:09.909 Core 1  2024.09.06 23:54:59   
2024.09.11 21:02:09.909 Core 1  2024.09.06 23:54:59   database error, FOREIGN KEY constraint failed
2024.09.11 21:02:09.909 Core 1  2024.09.06 23:54:59   CDatabase::Execute | ERROR: 5619 in query
2024.09.11 21:02:09.909 Core 1  2024.09.06 23:54:59   INSERT INTO strategy_groups VALUES(0, 'EA_EG_EU (H1, M30, M15, 9x16 items)')
2024.09.11 21:02:09.909 Core 1  final balance 24603.99 USD

このエラーの意味と修正方法を教えてください。記事のクエリを使用してテーブルがデータベースに追加されました。

 

ユーリさん、あなたのコードに目を通したところ、CDatabase::Insert関数の少し前の部分でエラーが発生しているようです:

2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59   CDatabase::Insert | ERROR: Reading row for request 
2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59   INSERT INTO passes VALUES (NULL, 0, 0, 10000.00,0.00,11096.20,21542.31,-10446.11,92.51,-63.35,630.89,39.00,444.04,53.00,-376.27,52.00,-376.27,52.00,9430.69,569.31,5.69,5.69,569.31,9325.11,683.96,6.83,6.83,683.96,2.15,2.06,16.22,3.44,3736.76,8435.00,5170.00,3042.00,2128.00,2766.00,2404.00,1706.00,1336.00,6.00,4.00,99.11,8122.90,'class CVirtualStrategyGroup([
2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59           class CVirtualStrategyGroup([
2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59           class CVirtualStrategyGroup([
2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59           class CSimpleVolumesStrategy("CADCHF",16385,220,1.40,1.70,150,2200.00,200.00,46000,24)
2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59          ],66.401062),class CVirtualStrategyGroup([

.....

2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59          ],13.365410),class CVirtualStrategyGroup([
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59           class CSimpleVolumesStrategy("CADJPY",15,132,0.40,1.90,0,7200.00,600.00,45000,27)
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59          ],13.365410),
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59          ],2.970797),
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59          ],1.462074)',
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59   '',
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59   '2024.09.06 23:54:59') RETURNING rowid;
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59   failed with code 5039

実行できません

      if(DatabaseReadBind(request, row)) {

これは何に関連しているのでしょうか?第2段階はパスしており、テスト自体もパスしています(Expert Advisorのトレードとデータベースからのパスはロードされています)。

 

こんにちは、ビクター。

すぐに戻ってこのプロジェクトに 取り組み、私が見つけたエラーを整理しようと思います。見つけてくれてありがとう。あなたが以前に書いてくださったエラーのいくつかを再現することができました。それらは、後の部分で、あることを目的とした編集が行われたが、それに加えて、次の記事では考慮されなかった他のことにも影響を与えたという事実に関連していることが判明した。この影響がエラーを生んだ。次回の記事では、自動最適化のすべてのステップをもう一度確認し、検出されたエラーをすべて取り除く。