記事「多通貨エキスパートアドバイザーの開発(第1回):複数取引戦略の連携」についてのディスカッション

 

新しい記事「多通貨エキスパートアドバイザーの開発(第1回):複数取引戦略の連携」はパブリッシュされました:

取引戦略にはさまざまなものがあります。リスクを分散し、取引結果の安定性を高めるためには、複数の戦略を並行して適用することが有効かもしれません。ただし、それぞれのストラテジーが個別のエキスパートアドバイザー(EA)として実装されている場合、1つの取引口座でそれらの作業を管理することは非常に難しくなります。この問題を解決するのに合理的なのは、1つのEAで異なる取引戦略の運用を実装することです。

何が欲しいのか、何を持っているのかを決める必要があります。

私たちは次を持っています(あるいは、ほとんど持っています)。

  • 既製のEAコードまたは取引操作を実行するための定式化されたルールの形で提供される、様々な銘柄や時間枠で機能する様々な取引戦略
  • 初期入金
  • 最大許容ドローダウン

私たちは次を望んでいます。

  • 選択したすべてのストラテジーを1つの口座で複数の銘柄と時間枠で連携する
  • 入金をすべてに均等に、または指定された比率に従って分配する
  • 最大許容ドローダウンを遵守するために、建てたポジションの数量を自動的に計算する
  • 端末の再起動を正しく処理する
  • MetaTrader 5および4で起動する

オブジェクト指向のアプローチ、MQL5とMetaTrader 5の標準テスターを使用します。

目の前の課題はかなり大きいので、ステップごとに解決していきます。

作者: Yuriy Bykov

 
class CStrategy : public CObject {
protected:
   ulong             m_magic;          // マジック
   string            m_symbol;         // シンボル(取引商品)
   ENUM_TIMEFRAMES   m_timeframe;      // チャートの期間(タイムフレーム)
   double            m_fixedLot;       // オープンポジションのサイズ(固定)

public:
   // コンストラクタ
   CStrategy(ulong p_magic,
             string p_symbol,
             ENUM_TIMEFRAMES p_timeframe,
             double p_fixedLot);

   virtual int       Init() = 0; // 戦略の初期化 - OnInitイベント処理
   virtual void      Tick() = 0; // メインメソッド - OnTickイベント処理
};

コンストラクタがあるのに、なぜInitメソッドが必要なのか?

なぜか、彼らはすぐにTSクラスを1つのシンボルと時間枠に限定した。


その方が論理的だと思うのだが。

class SYSTEM
{
public:
  virtual void OnTick() {}
};
 
fxsaber #:

コンストラクタがあるのに、なぜInitメソッドが必要なのですか?

なぜか彼らはすぐにTSクラスを1つのシンボルと時間枠に限定した。

私は著者のアプローチが気に入った。記事の中にそのような一節がある:

Init()メソッドとTick()メソッドは純粋に仮想的に宣言されている(メソッド・ヘッダが= 0になった後)。つまり、これらのメソッドの実装をCStrategyクラスには書かないということです。このクラスをベースに、Init() メソッドと Tick() メソッドが必然的に存在し、特定の取引ルールの実装を含む子孫クラスを作成します。

そうすると、私が理解する限り、このクラスは抽象的な ものになります。

 
Denis Kirichenko #:

そうすると、私が理解している限りでは、そのクラスは抽象的な ものになる......。

そうなります。なぜか子孫で使われる。Deinitをしない(デストラクタがある)のであれば、Initをしない(コンストラクタがある)のは論理的です。

//+------------------------------------------------------------------+
//| コンストラクタ|
//+------------------------------------------------------------------+
CSimpleVolumeStrategy::CSimpleVolumeStrategy(
   ulong            p_magic,
   string           p_symbol,
   ENUM_TIMEFRAMES  p_timeframe,
   double           p_fixedLot,
   int              p_signalPeriod,
   double           p_signalDeviation,
   double           p_signaAddlDeviation,
   int              p_openDistance,
   double           p_stopLevel,
   double           p_takeLevel,
   int              p_ordersExpiration,
   int              p_maxCountOfOrders) :
   // 初期化リスト
   CStrategy(p_magic, p_symbol, p_timeframe, p_fixedLot), // 基本クラスのコンストラクタを呼び出す
   signalPeriod_(p_signalPeriod),
   signalDeviation_(p_signalDeviation),
   signaAddlDeviation_(p_signaAddlDeviation),
   openDistance_(p_openDistance),
   stopLevel_(p_stopLevel),
   takeLevel_(p_takeLevel),
   ordersExpiration_(p_ordersExpiration),
   maxCountOfOrders_(p_maxCountOfOrders)
{}

//+------------------------------------------------------------------+
//| エキスパート初期化関数
//+------------------------------------------------------------------+
int CSimpleVolumeStrategy::Init() {
// ティックボリュームを取得するためにインジケータをロードする。
   iVolumesHandle = iVolumes(m_symbol, m_timeframe, VOLUME_TICK);

// ティック・ボリュームのアレイ・レシーバーのサイズと必要なアドレッシングを設定する。
   ArrayResize(volumes, signalPeriod_);
   ArraySetAsSeries(volumes, true);

// 取引で注文を出すためのマジックナンバーを設定する
   trade.SetExpertMagicNumber(m_magic);

   return(INIT_SUCCEEDED);
}

そして、可能なTCを人為的に強く絞り込むことは、奇妙な解決策である。


また、OOPのせいで入力が面倒なのもよくわかる。これを取り除くのは良いことだ。

 

Init()は、コンストラクタから結果を返すことが不可能であるため、今のところ省かれている。しかし、ストラテジーの初期化の結果としてINIT_SUCCESS以外のものを返す必要がなくなる可能性もあります。そのため、将来的にこのメソッドが削除される可能性は十分にある。

シンボルと時間枠という形で必須のストラテジープロパティを割り当てるのは、意図的な制限です。設計上、複数のシンボルでの取引は、このクラスを継承する多くのインスタンスの働きによって行われますが、特定のインスタンスはそれぞれ単一のシンボルで動作します。このような制限によって妨げられるようなストラテジーにはまだ出会っていない。それどころか、これらのパラメーターは検討したすべての戦略で見つかったので、一度に基本クラスに入れることにしたのである。

しかし将来的には、(もしあれば)独立した単一シンボル戦略に分割できないような複数シンボル戦略も検討するつもりだ。基本クラスにシンボルと時間枠のプロパティがあっても、複数のシンボルと複数の時間枠を使う子クラスの実装に大きな支障はないと思います。

 
Yuriy Bykov プロパティを 持たせても、複数のシンボルと複数の時間枠を使う子クラスを実装することは妨げられないと思います。

100%邪魔にはなりません。不要な存在でしかない。OOPはアーキテクチャ上、一般的なものから特殊なものへという原則に従っている。あなたは一般的なもの(基本クラス)を "private "にした。そこで呼ばれるのはCStrategy::Tick()だけだが。

 
Denis Kirichenko #:

そして、私はこの著者のアプローチが気に入った。記事の中にこんな一節がある:

私が理解する限りでは、このクラスは抽象的な ものになるだろう......。

つまり、子クラスを取得するためだけに使われる。基本クラスCStrategyのオブジェクトを作る必要はない。しかし、CAdvisor::AddStrategy(CStrategy &strategy)メソッドで追加するExpert Advisorオブジェクトに子クラスのオブジェクトを渡すことができる。

 
Yuriy Bykov #:

Init()は、コンストラクタから結果を返すことが不可能であるため、今のところ省かれている。しかし、ストラテジーの初期化の結果としてINIT_SUCCESS以外のものを返す必要がなくなる可能性もあります。そのため、将来的にこのメソッドが削除される可能性は十分にあります。

コンストラクタで何か問題が発生した場合(インジケータ・ハンドルがチャージされない、メモリが割り当てられないなど)に備えて、このような共通変数を保持しておく人もいます。
static int CStrategy::InitFlag = INIT_FAILED;
 
fxsaber #:
コンストラクタで何か問題が発生した場合(インジケータ・ハンドルがチャージされていなかったり、メモリが確保されていなかったり)に備えて、このような共有変数を保持しておく人もいる。

ああ、そういうことはすでに考えてある。この方法でやってみます。

 
Yuriy Bykov #:

CAdvisor::AddStrategy(CStrategy &strategy)メソッドに追加するEAオブジェクトに、任意の子クラスオブジェクトを渡すことができる。

このように呼び出されたとき、このメソッドのシグネチャに悪態をつかないのはコンパイラのバグのようだ。

   expert.AddStrategy(new CSimpleVolumeStrategy(
                         magic_ + 1, "EURGBP", PERIOD_H1,
                         NormalizeDouble(0.34 * depoPart_, 2),
                         130, 0.9, 1.4, 231, 3750, 50, 600, 3)

このようにすべきです。

CAdvisor::AddStrategy(CStrategy* strategy)
 
CObject を継承。
class CStrategy : public CObject {

あなたはそれを使わない。

class CAdvisor : public CObject {
protected:
   CStrategy         *m_strategies[];  // 取引戦略の配列

CObjectを継承するのはよくあることなのだが。