記事"クロスプラットフォームEA: シグナル"についてのディスカッション

 

新しい記事 クロスプラットフォームEA: シグナル はパブリッシュされました:

この記事では、クロスプラットフォームEAで使用される CSignal および CSignals クラスについて解説します。 MQL4 と MQL5 の違いについて、トレードシグナルの評価に必要なデータがどのようにアクセスされるかを調べ、記述されたコードが両方のコンパイラと互換性があることを確認します。

現在のシグナルの生成に必要なその他の計算はすべて、CSignal および CSignals オブジェクトに移動されました。 したがって、あとはCSignals がチェックを実行し、そのメソッドの CheckOpenLong と CheckOpenShort を呼び出してその出力を取得することだけです。 次のスクリーンショットは、MT4とMT5のエキスパートをテストした結果を示しています。

(MT4)

signal_ordermanager (mt4)

作者: Enrico Lambino

 

こんにちは、エンリコ。私の問題を解決するために、あなたの作品を拝見しています。StopBaseクラスをコンパイルすると、エラーのリストが表示されます。

implicit conversion from 'number' to 'string'   OrderStopBase.mqh       395     25
implicit conversion from 'number' to 'string'   OrderStopBase.mqh       467     26
implicit enum conversion        OrderStopBase.mqh       468     33
implicit enum conversion        OrderStop.mqh   37      33
implicit conversion from 'number' to 'string'   OrderStop.mqh   44      43
'COrderBase' - import not defined       OrderStop.mqh   54      7
'else' - semicolon expected     OrderStop.mqh   81      4
')' - unexpected token  OrderStop.mqh   81      46
implicit conversion from 'number' to 'string'   StopBase.mqh    767     22
implicit conversion from 'number' to 'string'   StopBase.mqh    774     28
implicit conversion from 'number' to 'string'   StopBase.mqh    796     22
implicit conversion from 'number' to 'string'   StopBase.mqh    803     28
implicit conversion from 'number' to 'string'   StopBase.mqh    698     36
'OrderType' - cannot convert enum       Stop.mqh        227     52
'StopLossCustom' - no one of the overloads can be applied to the function call  Stop.mqh        228     61
could be one of 2 function(s)   Stop.mqh        228     61
   double CStopBase::StopLossCustom(const string,const ENUM_ORDER_TYPE,const double)    StopBase.mqh    136     22
   bool CStopBase::StopLossCustom()     StopBase.mqh    99      22
'OrderType' - cannot convert enum       Stop.mqh        215     71
'TakeProfitCustom' - no one of the overloads can be applied to the function call        Stop.mqh        215     98
could be one of 2 function(s)   Stop.mqh        215     98
   double CStopBase::TakeProfitCustom(const string,const ENUM_ORDER_TYPE,const double)  StopBase.mqh    140     22
   bool CStopBase::TakeProfitCustom()   StopBase.mqh    111     22
implicit conversion from 'number' to 'string'   Stop.mqh        250     39
implicit enum conversion        Stop.mqh        291     31
implicit conversion from 'number' to 'string'   Stop.mqh        292     36

警告を無視すると、エラーはオーダータイプの問題から来ているようです。また、例のsignal_maをコンパイルすると、以下のエラーが発生します。

'GetPointer' - parameter conversion not allowed OrderStopVirtualBase.mqh        51      39
'GetPointer' - parameter conversion not allowed OrderStopVirtualBase.mqh        58      41
'=' - type mismatch     OrderStopsBase.mqh      106     23
'=' - type mismatch     OrderStopsBase.mqh      108     23
'=' - type mismatch     OrderStopsBase.mqh      110     23
'=' - type mismatch     OrderStopsBase.mqh      180     20
'=' - type mismatch     OrderStopsBase.mqh      182     20
'=' - type mismatch     OrderStopsBase.mqh      184     20

これらのエラーはどこから来ているのでしょうか? 関連する問題ですが、私の理解では、リスコフ代入は、スーパークラスがその基底クラスで代入できるように、インターフェイスにプログラムすることを規定しています。なぜオブジェクトを基底クラスで代用するのではなく、関数(それ自体がインターフェイスである)に渡すことにしたのですか?間違っているかもしれませんが、それがベストプラクティスではないでしょうか?

あなたの助けに感謝します。
 

シェパードさん、コメントありがとうございます。ご質問の件ですが

  1. 残念ながら、現時点ではStopBase.mqhを単独でコンパイルする方法はありません。MQL4およびMQL5コンパイラーは前方宣言を受け付けますが、前方宣言されたクラスのメソッドやメンバーにアクセスしようとするとエラーになります。StopBase.mqhをCOrderManagerやCExpertAdvisor(CStopとCStopsはこれら2つのクラスのコンポーネントです)などのはるかに大きなクラスとコンパイルする必要があります。
  2. タイプ・ミスマッチ・エラーについては、オリジナルのファイルでは見つけられませんでした(ソースはあなたの側で修正されたのでしょうか)。
  3. ほとんどの場合、ベース・クラスは問題なくクラス・メソッドに渡すことができると思います。エキスパートにライブラリを使わせる場合、基底クラスは存在しないと考えた方が楽でしょう。しかし、オブジェクトの中には、非仮想メソッドだけでなく、新しい仮想メソッドを持っているものもある。この2つのメソッドは、基底クラスだけではアクセスできない。基底クラスの代わりに派生クラスを使えば、コンパイラーは派生クラスの正しいバージョンを選択することができるので、派生クラスを使う方が基底クラスだけを使うよりも包括的です。
 
Enrico Lambino:

シェパードさん、コメントありがとうございます。ご質問の件ですが

  1. 残念ながら、現時点ではStopBase.mqhを単独でコンパイルする方法はありません。MQL4およびMQL5コンパイラーは前方宣言を受け付けますが、前方宣言されたクラスのメソッドやメンバーにアクセスしようとするとエラーになります。StopBase.mqhをCOrderManagerやCExpertAdvisor(CStopとCStopsはこれら2つのクラスのコンポーネントです)などのはるかに大きなクラスとコンパイルする必要があります。
  2. タイプ・ミスマッチ・エラーについては、オリジナルのファイルでは見つけられませんでした(ソースはあなたの側で修正されたのでしょうか)。
  3. ほとんどの場合、ベース・クラスは問題なくクラス・メソッドに渡すことができると思います。エキスパートにライブラリを使わせる場合、基底クラスは存在しないと考えた方が楽でしょう。しかし、オブジェクトの中には、非仮想メソッドだけでなく、新しい仮想メソッドを持っているものもある。この2つのメソッドは、基底クラスだけではアクセスできない。基底クラスの代わりに派生クラスを使えば、コンパイラーは派生クラスの正しいバージョンを選択することができるので、派生クラスを使う方が基底クラスだけを使うよりも包括的です。

こんにちは、エンリコ、

素早い回答をどうもありがとう。基底クラスの代わりに具象クラスを渡す理由は理解できます。C++では簡単な実装でも、MQLでは不可能なことがあります。

型の不一致に関しては、何も変更していません。単にダウンロードしてコンパイルしただけだ。あなたのアプローチは本当に素晴らしい。

私は自分のシステムをこのように開発した。シグナルを出力するシステムをストラテジーと考えました。 例えば、MAクロスオーバーの システムを持っているとします。しかし、ストラテジーはOnTickで呼び出されるのではなく、オブザーバー・パターンの一部として呼び出されます。 例えば、5分足の新しいバー、10Pip Renkoの新しいバーなど、特定のイベントが発生したときに更新されたり、呼び出されたりします。

あなたの知識と技術を共有するために時間を割いていただき、迅速な対応に改めて感謝します。

 

こんにちは、シェパード、

あなたの提案と洞察をシェアしてくれてありがとう。

あなたが取り組んでいることは素晴らしいアイデアだと思います。現在、このシリーズの最後の数記事(オーダーストップとストップを含む)を執筆中です。 ストップクラスが適しているかどうかはわかりません(実装次第です)。もし、オーダーマネージャーから 独立して動作させることができるのであれば、それはクラスオブジェクトを単純化するのに役立つので良いでしょう。しかし、あなたの仕事に役立つことを期待しています。

コンパイルについて:

  1. エラーなしでコンパイルできるのは、メイン・ソース/ヘッダー・ファイルとベース・クラス・ファイルだけです(前方宣言を使用しているものは例外です)。例題で、ベース・ファイル用のヘッダー・ファイルに#includeディレクティブを使用したのはこのためです(言語固有のファイルではありません)。
  2. 正しいコンパイラーを使用すべきである(MQL4コンパイラーでmq5ファイルをコンパイルすると、コンパイラー・エラーにつながる)。
 

こんにちは、エンリコ、

御社のシグナルモジュールをテストしています。SHORTシグナルとNEUTRALシグナルを1つずつ持っています。最終的にCMD_VOIDが表示されたのはなぜですか?CMD_VOIDはいつ現れるのですか?

実はこれはCSignalsBase::Checkで 表示されます。

if(signal.Entry())
        {
         if(m_signal_open>CMD_VOID)
           {
            ENUM_CMD signal_open=signal.SignalOpen();
            if(m_signal_open==CMD_NEUTRAL)
              {    
               m_signal_open=signal_open;
              }
            else if(m_signal_open!=signal_open)
              {               
               m_signal_open=CMD_VOID;
              }
           }
        }

シグナルは2つしかない。前のシグナルはCMD_SHORT。現在のシグナルはCMD_NEUTRALです。CMD_SHORTとCMD_NEUTRALが結果としてCMD_VOIDを与えることを確認できますか?

最初の信号がCMD_NEUTRALで、2番目の信号がCMD_SHORTの場合、合計の信号はCMD_SHORTになります。しかし、最初のシグナルがCMD_SHORTで2番目のシグナルがCMD_NEUTRALの場合、CMD_VOIDとなります。

こんな感じだろうか:

if(signal.Entry())
        {
         if(m_signal_open>CMD_VOID)
           {
            ENUM_CMD signal_open=signal.SignalOpen();
            if(m_signal_open==CMD_NEUTRAL)
              {    
               m_signal_open=signal_open;
              }
            else if(m_signal_open!=signal_open && signal_open!=CMD_NEUTRAL)
              {               
               m_signal_open=CMD_VOID;
              }
           }
        }
 
if(m_new_signal)
     {
      if(m_signal_open==m_signal_open_last)
         m_signal_open = CMD_NEUTRAL;
      if(m_signal_close==m_signal_close_last)
         m_signal_close= CMD_NEUTRAL;
     }

これは終値シグナルという点では完全には正しくない。なぜ同じ方向の終値シグナルが2つ存在できないのですか?

例えば、エントリーシグナルがショート、次のエグジットシグナルがロング(ショートを決済)、次のエントリーシグナルがロング、次のエントリーシグナルがショート、次のエグジットシグナルがロングです。この場合、最後のエグジットシグナルは、前のエグジットシグナルと同じ方向なので、機能しません。

 
mbjen:

これは終値シグナルという点では完全には正しくない。なぜ同じ方向の終値シグナルが2つ存在できないのですか?

例えば、エントリーシグナルがショート、次のエグジットシグナルがロング(ショートを決済)、次のエントリーシグナルがロング、次のエントリーシグナルがショート、次のエグジットシグナルがロングです。この場合、最後のエグジットシグナルは、前のエグジットシグナルと同じ方向なので、機能しません。

シグナルをどのように評価するかは、何を達成したいかによります。

あなたが投稿した最後のコードは、クラスメンバーm_new_signalがtrueに設定されているときにのみ実行されます。これは新しいシグナルでのみ取引するためです。この保護されたクラス・メンバーを設定するには、クラスで利用可能なメソッドNewSignalを使用します。

 
Enrico Lambino:

シグナルがどのように評価されるべきかについては、何を実現したかったかによります。

最後に投稿されたコードは、クラス・メンバーm_new_signalがtrueに設定されたときのみ実行されます。これは、新しいシグナルのみで取引するためのものです。この保護されたクラス・メンバーを設定するには、クラスで利用可能なメソッドNewSignalを使用します。


それは分かっている。しかし、これをfalseに設定すると、エントリーシグナルにも影響します。エントリー・シグナルには問題ありませんが、エグジット・シグナルには使えません。エグジットシグナルはリバージョンであったり、エグジットシグナルであったりするので、同じ方向のエグジットシグナルが2つあるのは普通のことです。

 

m_signal_closeには、以前のシグナル値がSignalBase.mqhに保存されているようです。例えば、私はいくつかの終了シグナルを持っています。それを チェックしてCalculate()メソッドがfalseを返すと、前回の終了時のシグナル値が表示されます。

 

こんにちは、mbjen、

mbjen:

エンリコ、こんにちは、

シグナルモジュールをテストしています。SHORTとNEUTRALのシグナルを1つずつ持っています。最終的にCMD_VOIDが表示されたのはなぜですか?CMD_VOIDはいつ現れるのですか?

実はこれはCSignalsBase::Checkで表示されます。

シグナルは2つしかない。前のシグナルはCMD_SHORT。現在のシグナルはCMD_NEUTRALです。CMD_SHORTとCMD_NEUTRALが結果としてCMD_VOIDを与えることを確認できますか?

最初の信号がCMD_NEUTRALで、2番目の信号がCMD_SHORTの場合、合計の信号はCMD_SHORTになります。しかし、最初のシグナルがCMD_SHORTで2番目のシグナルがCMD_NEUTRALの場合、CMD_VOIDとなります。

こんな感じでしょうか:

最初の質問を見落としていました。今まで気づきませんでした。とても良いフィードバックでした。

ご指摘ありがとうございます。そうですね。コードを更新し、記事を修正します。

mbjen です:

それは分かっています。でもfalseにするとエントリーシグナルにも影響します。エグジット・ルールが異なる可能性があるためです。エグジットシグナルはリバージョンであったり、エグジットシグナルであったりするので、同じ方向のエグジットシグナルが2つあるのは普通のことです。

それは一理あります。しかし、例えば、MAクロスオーバーの時だけエグジットシグナルを出したい場合、これは必要でしょう。現在のコードよりも、2つのシグナルを分離したほうがいいと思います:

if(m_new_signal)
 {
  if(m_signal_open==m_signal_open_last)
  m_signal_open = CMD_NEUTRAL;
 }
if(m_new_signal_close)
 {
  if(m_signal_close==m_signal_close_last)
  m_signal_close= CMD_NEUTRAL;
 }
mbjen:

m_signal_closeには、以前のシグナル値がSignalBase.mqhに保存されているようです。例えば、終了シグナルがあります。それをチェックしてCalculate()メソッドがfalseを返すと、前回の終了時のシグナル値が返されます。

Calculateメソッドは仮想メソッドです。もしメソッドがfalseを返すのであれば、メソッド自体からこれらのクラス・メンバーをニュートラルにリセットする必要があります。