MetaTrader 5をダウンロードする

一連の指標シグナルに対する単純ベイズ分類器

15 9月 2017, 09:40
Stanislav Korotky
0
241

好きであろうとなかろうと、統計は取引において重要な役割を果たすものです。数字で満たされている基本的なニュースから取引報告書やテスト報告書までにおいて、統計による指標を避けることはできません。同時に、取引決断を行う際の統計の適用可能性に関する論文は、最も議論の余地のあるトピックの1つです。市場はランダムであるか?相場は変動しないか?分析の確率的アプローチは適用可能か?これは無期限に議論することができます。さまざまな観点、厳密な科学計算や印象的な図表を魚津資料やディスカッションは、インターネット上でもmql5.comサイトでも簡単に見つけることができます。しかし、トレーダーは通常、アプリケーションの側面、つまり、実際に取引の仕組みが取引端末でどのように機能しているかに興味があります 。本稿は、一連のテクニカル指標を用いて取引意思決定を行うという確率モデルへの実用的なアプローチの実証を試みます。理論は最小限、実行が最大限になります。

確率論の観点から様々な指標の可能性を評価し、指標委員が取引システムの勝率を高める能力を検証するが考え方です。

これには、任意の指標シグナルを処理するためのフレームワークと、検証の基礎となる単純なエキスパートを作成する必要があります。

作業指標としては標準的な指標を含めることが提案されていますが、他のカスタム指標も含めて分析することは可能です。

しかし、アルゴリズムを設計して実装する前にはまだ、理論がもうちょっと必要です。


条件付き確率モデルの紹介

本稿の題名は単純ベイズ分類器に言及します。これは、有名なベイズの公式に基づいており、ここでは簡単に考察します。この分類器が「単純」と呼ばれるのは、その公式によって記述されたランダム変数の独立性についての必要な仮定のためです。指標の独立性については後にお話ししますが、今のところはこれは公式自体についてです。

   (1)

ここで、Hはシステムの内部状態に関する仮説(ここでは市場と取引システムの状態に関する仮説)であり、Eは観測された事象(ここでは指標シグナル)であり、 それらを記述する確率は下の通りです。
  • P(H)は、観測の履歴から知られている先験的確率であり、状態Hの確率です。
  • P(E)は、存在するすべての仮説を考慮した事象Eの全確率であり、そのうちのいくつかは通常存在します(仮説は互いに素でなければならない、すなわち一度には1つのシステムの状態しか存在しないことには留意すべきです。 理論に掘り下げたい方のためのリンクが用意されています)。
  • P(E|H)は、仮説(状態)Hが真のときの事象Eの発生確率です。
  • P(H|E)は事象Eを観測するときの仮説(状態)Hの事後確率です。

一例として単純な取引システムを考えましょう。上向きの動き(買い)、下向きの動き(売り)、横向きの変動(待機)といった市場の状態は、通常、仮説Hとみなされます。予想される市場状態を表す指標のシグナルは、イベントEとして使用されます。

特定の指標シグナルについては、利用可能な履歴について公式(1)の右辺から確率を計算し、後で市場P(H|E)の最も可能性の高い状態を見つけることは容易です。

しかし、この計算には、統計を収集するための仮説と方法論のより明確な定義が必要です。これは、確率を得るための基礎として使用されます。

まず、取引が(ティックではなく)バーで行われているとします。取引の効率性は、利益、利益要因または他の特性の量によって評価することができます。しかし、わかりやすくするために、ここでは市場での負けに対する勝ちの比率を使用します。これは、システムの評価を直接、取引の成功確率に結びつけます(シグナル使用)。

また、取引システムはストップロス、テイクプロフィット、ストップロス トレイルを持たず、ロットサイズも変更されないことにします。これらのパラメータをすべてモデルに導入することはできますが、それによって確率の計算が大幅に複雑になり、多次元分布に変わってしまうでしょう。ポジション保持時間を取引システムの唯一のパラメータとします。言い換えれば、指標を用いて選択された方向にエントリーし、所定時間後に自動的にエグジットします。このアプローチは、相場の成長や落ち込みに関する仮説の正しさや虚偽を強調する点で優れています。仮説は、このように、セーフガードやクッションなしで純粋な形でテストされます。

簡素化の論点を冠するために、2つのより劇的なアクションを取ることにします。

上記のように、「買い」、「売り」、「待機」は通常、取引仮説とみなされますが、「待機」を省略すると、概論の一般性を失うことなく計算を大幅に削減することができます。このような単純化は、得られた結果の適用性に悪影響を及ぼよすうに見えるかもしれません。これは部分的には正しいです。しかし、このような単純化を行ってもまだ読み込まれている素材の量に注意を払うと、作業モデルを最初に取得し、後で徐々に細部を補うことが良いということに同意なさるかもしれません。確率密度を考慮してより複雑なモデルを構築したい方は、インターネット上で対応した研究を見つけることができます(Reasoning Methods for Merging Financial Technical Indicators(金融技術指標を結合するための推論方法)(英語) ではハイブリッド確率論的意思決定システムが記述されています)。

最後に、2番目と最終のアクションは「買い」状態と「売り」状態を1つにまとめるというものですが、これは「市場エントリー」という普遍的な意味を持ちます。一般に、異なる方向での指標シグナルはこれと同様に対称的に使用されます。例えば、指標による買われ過ぎ状態は売りシグナルになり、売られ過ぎ状態は買いシグナルになるといったことです。

言い換えれば、仮説Hは2つの方向(売買)のいずれかの市場エントリーに成功したこととなります。

これらの条件の下で、公式(1) の右辺の確率は、選択された相場履歴で以下のように計算することができます。


エントリーの成功はどのバーでも可能なので、方向の1つが利益を上げることになります(詳細は後述されますが、D1が作業時間枠として選択されているため、ここでのスプレッドは無視されます)。

P(E) = 指標シグナルを有するバーの数/バーの総数

P(E|H) = 収益性の高い取引方向に一致する指標シグナルのバーの数 / バーの総数

選択された指標のシグナルが出した注文が成功するための条件を示す確率は、単純化後に得られた公式を使用して、履歴について計算することができます。

   (2)

ここでNokは正しいシグナルの数で、Ntotalはシグナルの総数です。

この指標を計算するためのフレームワークは、少し後で実装されます。その時わかるように、この確率は通常0.5に近く、安定して0.5を超える条件を見つけるためには一定の研究を行う必要があります。しかし、大きな値を持つ指標はまれです。主に研究していく標準指標については、この確率は0.51〜0.55の範囲で変化します。そのような値は小さ過ぎて、預金は定常的に増加するかわりにむしろ「引き分けになる」可能性が高いことは明らかです。

この問題を解決するには、1つではなく複数の指標を使用する必要があります。この判断はそれ自体では新しいものではなく、ほとんどのトレーダーによって実践されています。しかし、確率論は、異なる組み合わせの指標の効率の定量分析を行って潜在的な効果を評価することを可能にします。

指標が3つ(A、B、C)の場合、公式 (1) は以下のようになります。

  (3)

これはアルゴリズム計算に便利な形式にされる必要があります。幸いにも、ベイズの理論は多くの産業に応用されており、我々のケースのための既製のレシピを見つけることは可能です。

特に、単純ベイズスパムフィルタリングのようなフィールドがあります。詳細を勉強する必要はありません。関連しているのは基本的な概念のみです。文書(電子メールメッセージなど)は特定の特徴的な単語が含まれているとスパムとみなされます。言語内の単語の一般的な出現及びそれらをスパムで見つける確率はわかっています。同様に、指標シグナルの一般的な確率とその「ヒット」率もわかっています。言い換えれば、スパム処理理論を確率論的貿易理論に完全に適合させるには、「スパム」仮説を「成功取引」に置き換え、「単語」事象を「指標シグナル」に置き換えるだけで十分です。

すると、公式(3)は、個々の指標の確率を次のように拡張することができます(上記の計算を参照)。

   (4)

P(H|A)、P(H|B)、P(H|C) の計算は、公式(2) に従って各指標で別々に実行されます。

もちろん、必要なときには公式(4)を任意の数の指標に拡張することは容易です。指標数が正しい取引決定の確率にどのように影響するかを知るために、以下のようにすべての指標は同じ確率値を有すると仮定します。



すると公式(4)は以下となります。

   (5)

ここではNが指標数です。

図1は、様々なNの値に対するこの関数のグラフを示します。

異なる数の確率変数を用いた結合確率

図1 異なる数の確率変数を用いた結合確率

したがって p = 0.51 では P(3) = 0.53 となり、これは印象的ではありませんが、p = 0.55 では P(3) = 0.65 でこれは大幅な改善です。


指標の独立性

上記の公式は、分析されたランダムプロセスの独立性を前提としています。この場合でのプロセスは指標シグナルです。しかし、この条件は満たされているのでしょうか。

明らかに、標準指標の多くを含むいくつかの指標には共通点が多いです。図2は視覚的な例として組み込み指標のいくつかを示しています。

類似の標準指標グループ

図2 類似の標準指標グループ

最後のウィンドウで互いに重ね合わされた同じ期間のストキャスティクとWPR指標がお互いにほぼ反復していることは容易に分かります。それらの公式は算術的に同等であるので、これは驚くべきことではありません。

スクリーンショット内の少し上で、移動平均型のために修正されているMACDとオーサムオシレータはまったく同じです。さらに、両方とも移動平均(MA)に基づいてプロットされているため、MA自体と独立して呼び出すことはできません。

RSI、RVI、CCIも強く相関しています。事実上すべての標準オシレータが類似していて相関係数は1に近いことには留意すべきです。

また、ボラティリティ指標、特にATRとStdDevの間には顕著な偶然性があります。

独立していない指標の委員会は実際的には、実際に期待される理論的予測値よりもはるかに低効果であるため、取引システムのための一連の指標を形成する際には、これをすべて考慮する必要があります。

ところで、ニューラルネットワークを訓練するときにも同じ状況が発生します。トレーダーはしばしば、多くの自発的に選択された指標からのデータを処理しようとします。しかしながら、依存ベクトルを入力として与えることによってネットワークの計算能力が無駄になり、訓練の有効性は著しく低下します。分析されたデータの量は多く見えるかもしれませんが、それらに含まれる情報は重複していて無意味です。

この問題に対する厳密なアプローチは、最小のペアワイズ値を有する指標と形成されたセットとの間の相関を計算することを必要とします。これは独立した研究領域です。興味のある方は、インターネット上で関連記事を見つけることができます。ここでは、上記の観察に基づいた一般的な考え方に従います。例えば、セットの1つは、ストキャスティク、ATR、ACオシレータまたはWPR、ボリンジャーバンド、モーメンタムかもしれません。

ここでは、ACオシレータは本質的にオシレータに由来することに注意してください。グループに含めるのに適しているのはなぜでしょうか。

一連の相場(またはそれらに由来するオシレータ)を、周期的オシレータ(例えば、コサインまたはサイン)として簡略化して表現してみましょう。これらの関数の導関数は次のようになります。

   (6)



これらの関数とその派生関数の相関はゼロです。

    (7)


したがって、指標の1次導関数の使用は、一般的に、追加の独立指標として検討するための良い候補となります。

一方、2次導関数は、元のシグナルの複製である可能性が高いため、このような振動プロセスでは疑わしい候補となります。

指標の独立性に関する議論を要約すると、異なる期間で計算された指標のコピーが独立しているとみなすことができるかどうかが重要です。

答えは期間の比率に依存すると仮定することができます。わずかな違いは明らかに指標の依存性を保持しているため、顕著な違いが必要です。これは、エルダーのトリプルスクリーン法などの古典的方法と部分的に一致しています。通常、少なくとも5倍異なる時間枠は、異なる期間の指標の分析に相当します。

考慮されているシステムでは、独立変数は実際には指標値ではなくそれらによって直接生成された取引シグナルであることに注意してください。しかし、同じ種類(オシレータなど)の指標のほとんどの取引シグナル生成の原則は似ています。したがって、時系列の強い依存性または弱い依存性は、シグナルの強い依存性または弱い依存性と同等です。


設計

さて、理論を習ったので、何をどのようにコーディングするのかを学ぶ準備ができました。

指標の取引シグナルの統計は特別なエキスパートで収集されます。エキスパートが任意の指標の値に基づいて取引できるようにするには、そのフレームワーク(本質的にmqhヘッダーファイル)を実装する必要があります。このフレームワークでは、使用される指標とシグナル生成メソッドの説明が入力パラメーターとして渡されます。例えば、設定で異なる期間の2つの移動平均を設定し、高速MAが低速MAを上/下に横切るときに売/買シグナルを生成するオプションが必要です。

EAはバーの開始の明示的な管理を行い、始値のみで取引します。これは実際のエキスパートではなく、確率を計算して仮説をテストするためのツールです。指標セットには無限に多くのオプションがあるため、条件がすばやく満たされることが重要です。

デフォルトの作業時間枠としてはD1が使用されます。もちろん、他の時間枠での分析の実行を止めるものはありません。しかし、D1は最もランダム雑音の影響を受けにくいため、数年間存在する規則性の分析は確率論的アプローチの特異性を最も満たすものです。さらに、スプレッドは通常、D1の取引では無視され、システムの中間的な「待機」状態の解除を無効にします。しかし、日中取引の場合、そのような前提は立てられず、より多くの仮説の確率を計算する必要があります。

前述したように、EAは指標シグナルに基づいてポジションを開き、あらかじめ決められた時間が経過するとそれを決済します。この目的のために、対応する入力パラメータが導入され、そのデフォルト値は5日です。これはD1時間枠の特徴的な期間であり、D1を使用する取引についての多くの研究で使用されています。

EAとフレームワークはクロスプラットフォームになります。つまり、MetaTrader 4とMetaTrader 5の両方でのコンパイルと実行が可能です。この機能は、MetaTrader 5環境でMQL API MetaTrader 4を使用できる、公開されているラッパーヘッダーファイルによって提供されます。さらに、場合によっては条件付きコンパイルが使用されます。この場合、コードの特定の部分は、#ifdef __MQL4__ 及び #ifdef __MQL5__ プリプロセッサディレクティブでラップされます。


MQLでの実装

指標のフレームワーク

指標シグナルを処理するためのフレームワークの概要は、必要とされる指標の種類の考察から開始されます。最も明白な列挙体は、すべての組み込み指標とカスタム指標のiCustom項目を含むもので、フレームワークの入力パラメータを介して指標を選択するために必要となります。

enum IndicatorType
{
  iCustom,

  iAC,
  iAD,
  tADX_period_price,
  tAlligator_jawP_jawS_teethP_teethS_lipsP_lipsS_method_price,
  iAO,
  iATR_period,
  tBands_period_deviation_shift_price,
  iBearsPower_period_price,
  iBullsPower_period_price,
  iBWMFI,
  iCCI_period_price,
  iDeMarker_period,
  tEnvelopes_period_method_shift_price_deviation,
  iForce_period_method_price,
  dFractals,
  dGator_jawP_jawS_teethP_teethS_lipsP_lipsS_method_price,
  fIchimoku_tenkan_kijun_senkou,
  iMomentum_period_price,
  iMFI_period,
  iMA_period_shift_method_price,
  dMACD_fast_slow_signal_price,
  iOBV_price,
  iOsMA_fast_slow_signal_price,
  iRSI_period_price,
  dRVI_period,
  iSAR_step_maximum,
  iStdDev_period_shift_method_price,
  dStochastic_K_D_slowing_method_price,
  iWPR_period

};
各組み込み指標の名前には、指標自体のパラメータに関する情報を含む接尾辞が含まれています。要素の最初の文字は、使用可能なバッファの数を示します。例えば、i - 1つのバッファ、d - 2、t - 3です。これはすべてユーザーに対するヒントにすぎません。間違った数のパラメータまたは存在しないバッファのインデックスが指定された場合、フレームワークはログにエラーを出力します。

当然のことながら、各指標については、入力パラメータにその型を指定するだけでなく、データの読み取りを開始するための実際のパラメータを文字列、バッファ番号、及びバー番号として指定する必要があります。

指示値はシグナルを生成するために使用されます。理論的には、任意の数の異なるシグナルが存在する可能性がありますが、主なバリエーションは別の列挙体にまとめられます。

enum SignalCondition
{
  Disabled,
  NotEmptyIndicatorX,
  SignOfValueIndicatorX,
  IndicatorXcrossesIndicatorY,
  IndicatorXcrossesLevelX,
  IndicatorXrelatesToIndicatorY,
  IndicatorXrelatesToLevelX
};
したがって、シグナルは次の場合に形成されます。
  • 指標値が空でない
  • 指示値に必要な符号(正または負)がある
  • 指標が別の指標と交差する(シグナルを記述するときは、2つの指標を設定する必要があるのでご注意ください)
  • 指標が一定のレベルを横切る(ここでは、レベルに入るフィールドが必要であることが明らかになります)
  • 指標が別の指標に対して必要な方法で配置される(例えば、上または下)
  • 指標が所与のレベルに対して必要な方法で配置される

最初の要素 'Disabled' はシグナルを生成するための条件を無効にします。シグナルを記述するための入力パラメータのいくつかの同一のグループを提供し、各シグナルはデフォルトでは無効にされます。

以前の列挙項目の名前から、値と行の位置の必要な符号を互いに何らかの形で設定する必要があることを容易に推測できます。この目的のために別の列挙が追加されます。

enum UpZeroDown
{
  EqualOrNone,
  UpSideOrAboveOrPositve,
  DownSideOrBelowOrNegative,
  NotEqual
};
EqualOrNoneは下記の確認を可能にします。
  • SignOfValueIndicatorXと組み合わせて空の値
  • IndicatorXrelatesToLevelXと組み合わせてレベルへの等しさ

UpSideOrAboveOrPositveは下記の確認を可能にします。

  • IndicatorXcrossesIndicatorYとの上向き交差
  • SignOfValueIndicatorXとの値が正であること
  • IndicatorXcrossesLevelXとのレベルの上向き交差
  • XとYが同じ指標の場合、IndicatorXrelatesToIndicatorYとの連続バーの指標値の増加
  • XとYが異なる指標である場合、IndicatorXrelatesToIndicatorYとのXの位置がYよりも上にあること
  • 指標の位置がIndicatorXrelatesToLevelXのレベルを上回っていること

DownSideOrBelowOrNegativeは下記の確認を可能にします。

  • IndicatorXcrossesIndicatorYとの下向き交差
  • SignOfValueIndicatorXとの値が負であること
  • IndicatorXcrossesLevelXとのレベルの下向き交差
  • XとYが同じ指標の場合、IndicatorXrelatesToIndicatorYとの連続バーの指標値の減少
  • XとYが異なる指標である場合、IndicatorXrelatesToIndicatorYとのXの位置がYよりも下にあること
  • 指標の位置がIndicatorXrelatesToLevelXのレベルを下回っていること

NotEqualは下記の確認を可能にします。

  • IndicatorXrelatesToLevelXのレベル(値)と等しくないこと

トリガされたシグナルは処理されなければなりません。これを行うために特別な列挙体を定義しましょう。

enum SignalType
{
  Alert,
  Buy,
  Sell,
  CloseBuy,
  CloseSell,
  CloseAll,
  BuyAndCloseSell,
  SellAndCloseBuy,
  ModifyStopLoss,
  ModifyTakeProfit,
  ProceedToNextCondition
};
メッセージ出力、すべての未決済注文(買い、売り、またはその両方)の買い、売り、決済、売りから買いへのポジションの逆転、買いから売りへのポジションの逆転、ストップロス値やテイクプロフィット値の修正、 また、次の条件(シグナル)の確認への移行は、シグナル処理における主要アクションです。最後のポイントでは、シグナルの確認を連鎖させることができます(例えば、メインバッファがシグナルラインを越えていないかどうかを確認し、そうであれば、それが特定のレベルを上回っているか下回っているかを調べるなど)。

アクションリストに未決注文の配置が含まれていないことがわかります。これはこの作業の範囲外です。興味のある方は、フレームワークを広げてください。

これらの列挙がすべて利用可能であるため、作業指標の設定に使用される特定の属性グループを記述することができます。1つのグループは次のようになります。

input IndicatorType Indicator1Selector = iCustom; // ·     セレクタ
input string Indicator1Name = ""; // ·     名前
input string Parameter1List = "" /*1.0,value:t,value:t*/; // ·    パラメータ
input string Indicator1Buffer = ""; // ·     バッファ
input int Indicator1Bar = 1; // ·     バー
Indicator1Nameパラメータは、Indicator1SelectorがiCustom.に設定されているときにカスタム指標の名前を設定するために設計されています。

Parameter1Listパラメータは、指標パラメータをカンマで区切られた文字列として設定することができます。各入力パラメータの型は自動的に検出されます(例: 11.0 — double、11 — int、2015.01.01 20:00 — datetime、true/false — bool、"text" — string)。特定のパラメータ(移動平均や価格の種類など)は、数値ではなく、引用符のない文字列で設定できます(sma、ema、smma、lwma、close、open、high、low、median、typical、weighted、lowhigh、closeclose)。

Indicator1Bufferは引用符なしでのバッファの番号または名前です。サポートされているバッファ名は、main、signal、upper、lower、jaw、teeth、lips、tenkan、kijun、senkouA、senkouB、chikou、+ di、-diです。

Indicator1Bar — バーの数です(デフォルトは1)。

指標がすべて定義されると、それらはシグナルを形成するための基準、すなわちイベントをトリガするための条件として使用することができます。各シグナルは、入力パラメータのグループによって定義されます。

input string __SIGNAL_A = "";
input SignalCondition ConditionA = Disabled; // ·     条件A
input string IndicatorA1 = ""; // ·     シグナルAの指標X
input string IndicatorA2 = ""; // ·     シグナルAの指標Y
input double LevelA1 = 0; // ·     シグナルAのレベルX 
input double LevelA2 = 0; // ·     シグナルAのレベルY
input UpZeroDown DirectionA = EqualOrNone; // ·     方向または符号A
input SignalType ExecutionA = Alert; // ·     アクションA
各シグナルの識別子は __SIGNAL_ パラメータに設定することができます。

'Condition' はシグナルを確認する条件を選択します。次に、1つまたは2つの指標と1つまたは2つのレベルの値を使用するように設定します(2番目のレベルは将来のために予約されており、この実験では使用されません)。'Indicator' パラメータの指標は、対応する属性グループからの指標番号、または以下の形式の指標プロトタイプです。

indicatorName@buffer(param1,param2,...)[バー]

この入力形式では、属性グループを使用した詳細な説明なしで、使用済区分を迅速に決定することができます。例として

iMA@0(1,0,sma,high)[1]

は高値を返します。バー#1は、作業中のエキスパートの現在のバー(最終的な高値が分かっている最新の完全なバー)です。

したがって、指標は、属性の専用グループ(後でシグナルから数で参照する)と、直接シグナルの'Indicator'パラメータとの両方で設定することができます。最初の方法は、同じ指標を異なるシグナルで使用する場合、または1つのシグナルの内部でXとYとして使用する場合に便利です。

'Direction'パラメータは、条件をトリガするための値の方向または符号を指定します。シグナルがトリガされると、 'Execution'に従って対応するアクションが実行されます。

次に、指標とシグナルを特定する例を示します。

現在フレームワークでは、指標が20以上のパラメータを持たないこと、指標属性を持つ専用グループの最大数が6であること(前に述べたように、シグナル内に指標を直接追加設定することができる)、及びシグナルは6つ以下であることが定義されています。これらはすべてソースコード内で変更できます。本稿末尾にはIndicatN.mqhファイルが添付されています。

このファイルにはさらに、指標パラメータの解析、呼び出し、条件の確認、確認結果の呼び出しコード(エキスパート)への戻り値など、すべてのロジックを含む複数のクラスが実装されています。

特に、上で検討したSignalType列挙体から特定のアクションを実行する必要性に関する指示を渡すには、単純なpublic TradeSignalsが使用されます。これには、列挙項目に対応するブール値フィールドが含まれます。

class TradeSignals
{
  public:
    bool alert;
    bool buy;
    bool sell;
    bool buyExit;
    bool sellExit;
    bool ModifySL;
    bool ModifyTP;
    
    int index;
    double value;
    
    string message;
  
    TradeSignals(): alert(false), buy(false), sell(false), buyExit(false), sellExit(false), ModifySL(false), ModifyTP(false), value(EMPTY_VALUE), message(""){}
};
必要な条件が満たされると、フィールドはtrueに設定されます。例えば、CloseAllアクションが選択されている場合、TradeSignalsオブジェクトにbuyExitフラグとsellExitフラグが設定されます。

'index'フィールドは、トリガされた条件のシリアル番号を含みます。

'value'フィールドは、例えば、指標値から得られる新しいストップロスレベルなど、カスタム値を渡すために使用できます。

最後に、 'message'フィールドにはユーザに状況を説明メッセージが入っています。

すべてのクラスの実装に関する詳細は、ソースコードにあります。添付されている補助fmtprnt2.mqh(ログに書式設定された出力)とRubbArray.mqh( 「ラバー」配列)ヘッダーファイルが使われます。

フレームワークヘッダーファイルは、#includeディレクティブを使用してエキスパートコードにインクルードされる必要があります。結果として、指標属性を持つ入力パラメータのグループはコンパイル後にEAの設定ダイアログに表示されます。

指標の設定

図3 指標の設定

下記はシグナル定義を含みます。

取引シグナル設定

図4 取引シグナル設定

スクリーンショットには既に前もって設定した値が表示されています。これらは、EAのコンセプトに移って特定の取引戦略の設定を開始すると、より詳細に検討されます。また、指標の属性を設定する際に、数値パラメータをtype =var1、= var2などの式で置き換えることが可能であることにも注意してください。それらは、最適化のために設計された同じ名前(var1、var2など)を持つフレームワークの特別な入力パラメータを参照します。例えば、

iMACD@main(=var4,=var5,=var6,open)[0]

は、MACDの高速、低速及びシグナル移動平均のパラメータがそれぞれvar4、var5及びvar6入力パラメータを介して最適化できることを意味します。また、最適化を無効にしても、1回のテスト実行中に、指標の対応する属性の値がフレームワークの指定された入力パラメータから読み取られます。

エキスパートの検証

コーディングを容易にするために、すべての取引関数を特別なクラスに移して、それを別のExpert0.mqhヘッダーファイルとして整理しましょう。検証されるのは非常に単純な取引システムがなので、クラスではポジションを開くことと決済することのみが許可されます。

したがって、指標と取引に関連するすべての単調な操作は、ヘッダファイルに移動されます。

#include <IndicatN.mqh>
#include <Expert0.mqh>
indstats.mq4ファイル自体には数行のコードと単純なロジックしかありません。

EAは拡張子をmq5に変更した後はMetaTrader 5でコンパイル及び動作できることになっているので、コードを新しい環境に移行するヘッダファイルを追加しましょう。

#ifdef __MQL5__
  #include <MarketMQL4.mqh>
  #include <ind4to5.mqh>
  #include <mt4orders.mqh>
#endif

ここでエキスパートの入力パラメータを見ていきます。

input int ConsistentSignalNumber = 1;
input int Magic = 0;
input float Lot = 0.01f;
input int TradeDuration = 1;

  

Expert0.mqhファイルからエキスポートオブジェクトを作成するには、 'Magic'と 'Lot'が必要です。

Expert e(Magic, Lot);

ConsistentSignalNumberパラメータには、堅牢性を高めるために組み合わせられる取引シグナルの数が含まれます。

TradeDurationパラメータは、ポジションを保持するバーの数を設定します。前述したように、注文はシグナルに従って出され、D1時間枠が使用されるので、5バー、すなわち5日後には取引が終了します。

OnInitイベントハンドラは指標フレームワークを初期化します。

int OnInit()
{
  return IndicatN::handleInit();
}

OnTickハンドラはバーの開きを制御します。

void OnTick()
{
  static datetime lastBar;
  
  if(lastBar != Time[0])
  {
    const RubbArray<TradeSignals> *ts = IndicatN::handleStart();
    ...
    lastBar = Time[0];
  }
}

  

新しいバーの作成中に、指標フレームワークを再度呼び出して、すべての指標と関連する条件を確認します。これにより、トリガされたシグナルの配列が生成されます。これがTradeSignalsオブジェクトです。

ここで統計の蓄積についてお話しします。

いったん満たされると、フレームワークの各条件(イベント)は、デフォルトで 'alert'フラグを持つシグナルを生成します。これは、指標からのシグナル数、及びシステムの充足状態の数、すなわち、売買が成功するケース(バー)の数を数えるするために使用されます。

統計を計算するために、配列について説明します。

int bars = 0; // バー/サンプルの総数
int bull = 0, bear = 0; // 取引の種類ごとのバー/サンプルの数
int buy[MAX_SIGNAL_NUM] = {0}, sell[MAX_SIGNAL_NUM] = {0};  // 無条件シグナル配列
int buyOnBull[MAX_SIGNAL_NUM] = {0}, sellOnBear[MAX_SIGNAL_NUM] = {0}; // 条件付き(成功)シグナル配列
バーによる取引の場合、各バーは5バーにおよぶ取引への潜在的な新しいエントリです。そのようなセグメントは、相場の上昇または下降によって特徴付けられ、それぞれ強気または弱気としてマークされます。

すべての売買シグナルは、「買い」及び「売り」配列で合計されます。対応するシグナルがセグメントの「強気」または「弱気」と一致する場合、種類に応じてbuyOnBullまたはsellOnBear配列にも蓄積されます。

下記のOnTick内のコードが配列に書き込みます。

    const RubbArray<TradeSignals> *ts = IndicatN::handleStart();
    bool up = false, down = false;
    int buySignalCount = 0, sellSignalCount = 0;
    
    for(int i = 0; i < ts.size(); i++)
    {
      // アラートを使用して統計情報を収集する
      if(ts[i].alert)
      {
        //  iで列挙されたイベントを設定している間
        // 仮説H_xxxはシグナルS_xxxより先に来るべきである
        // ここでアップマークまたはダウンマークを付けるのが理由である
        if(IndicatN::GetSignal(ts[i].index) == "H_BULL")
        {
          bull++;
          buy[ts[i].index]++;
          up = true;
        }
        else if(IndicatN::GetSignal(ts[i].index) == "H_BEAR")
        {
          bear++;
          sell[ts[i].index]++;
          down = true;
        }
        else if(StringFind(IndicatN::GetSignal(ts[i].index), "S_BUY") == 0)
        {
          buy[ts[i].index]++;
          if(up)
          {
            if(PrintDetails) Print("buyOk ", IndicatN::GetSignal(ts[i].index));
            buyOnBull[ts[i].index]++;
          }
        }
        else if(StringFind(IndicatN::GetSignal(ts[i].index), "S_SELL") == 0)
        {
          sell[ts[i].index]++;
          if(down)
          {
            if(PrintDetails) Print("sellOk ", IndicatN::GetSignal(ts[i].index));
            sellOnBear[ts[i].index]++;
          }
        }
        
        if(PrintDetails) Print(ts[i].message);
      }
    }
トリガされたシグナルの配列を取得した後は、ループでその要素を反復処理します。有効にされた 'alert'フラグは、統計情報の収集を示すものでした。

コードをより深く分析する前に、シグナル(イベント)の名前付けに関する特別なきまりを紹介しましょう。市場の強気相場または弱気相場の仮説には、H_BULLとH_BEARの識別子が付けられます。これらのイベントは、他のイベント(指標シグナル)の前に、まずフレームワークの入力パラメータを使用して定義する必要があります。これは、確認された仮説に基づいて適切な特性(ブール変数'up'と'down')を設定するために必要です。

指標シグナルには、S_BUYまたはS_SELLで始まる識別子が必要です。

ここでわかるように、アクティブにされたイベントts[i].indexの番号への参照を使用して、その識別子はGetSignal関数を呼び出すことによって得られます。仮説が満たされた場合、強気または弱気のセグメントの一般的なカウンターが更新されます。シグナル生成の場合、シグナルの種類ごとに合計数が数えられ、成功指標、つまり現在の仮説と一致した指標の数も数えられます。

それぞれのバーにはH_BULL仮説かH_BEAR仮説のどちらかが当てはまることを覚えておいてください。

EAは、統計収集以外にも、シグナルによる取引をサポートする必要があります。この目的のために、ループボディには'buy' フラグと'sell'フラグの確認が追加されます。

      if(ts[i].buy)
      {
        buySignalCount++;
      }
      else
      if(ts[i].sell)
      {
        sellSignalCount++;
      }
取引機能は、ループの後に実装されます。まず、ポジションは(存在する場合は)指定された期間が経過した後に決済されます。
    if(e.getLastOrderBar() >= TradeDuration)
    {
      e.closeMarketOrders();
    }

  

そして、ジョイントシグナルに応じて売買が行われます。

    if(buySignalCount >= ConsistentSignalNumber
    && sellSignalCount >= ConsistentSignalNumber)
    {
      Print("Signal collision");
    }
    else
    if(buySignalCount >= ConsistentSignalNumber)
    {
      e.closeMarketOrders(e.mask(OP_SELL));
      
      if(e.getOrderCount(e.mask(OP_BUY)) == 0)
      {
        e.placeMarketOrder(OP_BUY);
      }
    }
    else
    if(sellSignalCount >= ConsistentSignalNumber)
    {
      e.closeMarketOrders(e.mask(OP_BUY));
      
      if(e.getOrderCount(e.mask(OP_SELL)) == 0)
      {
        e.placeMarketOrder(OP_SELL);
      }
    }
売買シグナルが互いに矛盾する場合、そのような状態はスキップされます。売買シグナルの数が所定数のConsistentSignalNumber以上であれば、対応する注文が開かれます。

ConsistentSignalNumberの値を設定されたシグナルの数よりも小さく設定することによって、すべてまたはほとんどの戦略を組み合わせたモードで取引システムをテストできることには言及するべきです。通常の動作モードでは、ジョイントイベントを検出するためにはConsistentSignalNumberはシグナル数と完全に等しくなければならないため、EAは積集合を使用しますが和集合は使用しません。例えば、3つのシグナルが設定され、ConsistentSignalNumberが3に設定されている場合、3つのイベントがすべて同時に発生した場合にのみ取引が実行されます。ConsistentSignalNumberが1に設定されている場合、3つのシグナルのいずれか(少なくとも1つ)が受信されると注文が出されます。

OnDeinitハンドラは、収集したアラートの統計情報または注文履歴をログに出力します。

エキスパートの完全なソースコードは、indstats.mq4ファイルにあります。


取引シグナル設定

他のすべてのシグナルは、買いまたは売りに関する2つの仮説と照合しなければなりません。これを行うには、H_BULLシグナルとH_BEARシグナル及びその指標を設定します。

バーの価格を取得するには、期間が1のiMA指標を使用します。 __INDICATOR_1グループで下記を設定します。

Selector = iMA_period_shift_method_price

Parameters = 1,0,sma,open

Buffer = 0

Bar = 0

__INDICATOR_2グループでは、バー数を除いて同様の設定を行います。TradeDurationパラメータで使用するバーの数は5に設定する必要があります。

言い換えれば、エキスパートは統計収集モードでは取引しません。代わりに、使用されている価格の種類に応じて、5番目と6番目のバーの指標シグナルだけでなく、5番目と6番目のバー間の相場の変化を分析します。値は、始値に基づいて作業する指標の場合は5番目のバー、その他の指標では6番目のバーから取られます。統計収集モードでは、バー#5はバーチャルの現在バーであり、その後のすべてのバーは、強気または弱気市場における仮説の「未来の」達成に関する情報を提供します。

取引モードでは、シグナルはバー#0(指標が始値に基づいている場合)またはバー#1(その他の場合)から取られることには注意が必要です。エキスパートが始値を使用していないが、代わりにティックを分析した場合は、バー#0で指標値を確認する必要があります。

統計収集と取引の2つのモードが存在するということは、作業バーの数が異なるさまざまなパラメータセットを作成する必要があることです。ここでは、統計を収集するためのセットから始め、それを実際の取引セットに簡単に変換します。

仮説を構成するためにはこれらの2つのMA指標が使用されます。group __SIGNAL_Aでは下記を入力します。

__SIGNAL_A = H_BULL
Condition = IndicatorXrelatesToIndicatorY Indicator X = 1 Indicator Y = 2 Direction or sign = UpSideOrAboveOrPositve Action = Alert

__SIGNAL_Bグループは、方向を除いて同様に構成されます。

__SIGNAL_B = H_BEAR
Direction or sign = DownSideOrBelowOrNegative

確率的な取引モデルをテストするためには下記の3つの標準指標ベースの戦略が使用されます。

  • ストキャスティクス
  • MACD
  • ボリンジャーバンド

フレームワークのこの機能を示すために、すべての指標のパラメータが最適化されており、その一部が意図的に入力パラメータvar1、var2などへの参照として残されていることを前もって述べておく必要があります。お使いのプロバイダーのデータで肯定的な結果を再現するには、それぞれの戦略を再最適化する必要があります。

ストキャスティクスベースの戦略では、指標がレベル20を上向きに交差するときに買って、80レベルを下向きに交差するときに売ります。これには __INDICATOR_3グループを下記のように定義します。

Selector = dStochastic_K_D_slowing_method_price
Parameters = 14,3,3,sma,lowhigh Buffer = main Bar = 6

指標には高値と安値が使用されているため、バー#6を取る必要があります。これは、シグナルがトリガされた場合にバーチャル取引が開始されるバー#5の前の最新のバーです。

売買シグナルは、確率的指標に従って調整されます。買いのためのグループ:

__SIGNAL_C = S_BUY stochastic
Condition = IndicatorXcrossesLevelX Level X = 20 Direction or sign = UpSideOrAboveOrPositve

売りのためのグループ:

__SIGNAL_D = S_SELL stochastic
Condition = IndicatorXcrossesLevelX Level X = 80 Direction or sign = DownSideOrBelowOrNegative

MACDベースの戦略では、メインラインがシグナルラインを上向きに交差するときに買って、下向きに交差するときに売ります。

__INDICATOR_4指標のグループを下記のように構成します。

Selector = dMACD_fast_slow_signal_price
Parameters = =var4,=var5,=var6,open Buffer = signal Bar = 5

期間 'fast'、 'slow'、 'signal'は、最適化のために利用可能な変数var4、var5、var6から読み込まれます。これらは現在、それぞれ6、21、6に設定されています。指標は始値に基づいてプロットされているため、バー#5が使用されます。

指標を構成するグループの数は限られているため、「メイン」バッファはシグナル内で直接定義されます。買いのためのグループ:

__SIGNAL_E = S_BUY macd
Condition = IndicatorXcrossesIndicatorY Indicator X = iMACD@main(=var4,=var5,=var6,open)[5] Indicator Y = 4 Direction or sign = UpSideOrAboveOrPositve

売りのためのグループ: 

__SIGNAL_F = S_SELL macd
Condition = IndicatorXcrossesIndicatorY Indicator X = iMACD@main(=var4,=var5,=var6,open)[5] Indicator Y = 4 Direction or sign = DownSideOrBelowOrNegative

ボリンジャーバンドベースの戦略は、前のバーの高値が2バー右にシフトされた指標の上の線を上回るときに買い、前のバーの低値が2バー右にシフトされた指標の下の線を下回るときに売ります。以下は2つの指標線の設定です。

__INDICATOR_5:

Selector = tBands_period_deviation_shift_price

Parameters = =var1,=var2,2,typical
Buffer = upper Bar = 5

__INDICATOR_6:

Selector = tBands_period_deviation_shift_price
Parameters = =var1,=var2,2,typical Buffer = lower Bar = 5

期間と偏差は、var1とvar2にそれぞれ7と1で指定されています。バー#5は、典型的な価格タイプであるにもかかわらず、両方の場合に使用することができます。なぜなら、指標線は2バー右にシフトされている、すなわち実際に過去のデータに対して計算されるからです。

最後に、シグナルを設定するためのグループは以下のようになります。

__SIGNAL_G = S_BUY bands
Condition = IndicatorXcrossesIndicatorY Indicator X = iMA@0(1,0,sma,high)[6] Indicator Y = 5 Direction or sign = UpSideOrAboveOrPositve
__SIGNAL_H = S_SELL bands
Condition = IndicatorXcrossesIndicatorY Indicator X = iMA@0(1,0,sma,low)[6] Indicator Y = 6 Direction or sign = DownSideOrBelowOrNegative

すべての設定は、本稿末尾に.setファイルとして添付されています。


結果

指標による統計

確率を計算するために、EURUSD D1ペアの期間2014.01.01-2017.01.01の統計が使用されます。統計収集モードのEA設定は、indstats-stats-all.setファイルに含まれています。

収集されたデータはログに出力されます。以下はその例です。

: bars=778
: bull=328 bear=449
:    buy:    328      0     30      0     50      0     58      0 
:  buyOk:      0      0     18      0     29      0     30      0 
:   sell:      0    449      0     22      0     49      0     67 
: sellOk:      0      0      0     14      0     28      0     41 
: totals:   0.00   0.00   0.60   0.64   0.58   0.57   0.52   0.61 
: Stats by name:
:  macd=0.576 [57/99]
:  bands=0.568 [71/125]
:  stochastic=0.615 [32/52]

バーの総数は778で、そのうちの328は5日間の買い取引にの成功、449は5日間の売り取引の成功に適していました。最初の2つの列には仮説カウンタが含まれています(同じ2つの数字)。列の次のペアは、それぞれの取引戦略を参照しています。これらの戦略のそれぞれは、買い取引の列と売り取引の列によって表されます。例えば、ストキャスティクスベース戦略は30の買いシグナルを生成してそのうち18は収益性があり、22の売りシグナルのうち14は収益性がありました。成功したシグナルの総数を合計して生成されたシグナルの数で除算すると、それぞれの効率値(履歴データに基づく成功確率)が得られます。

  • ストキャスティクス — 0.615
  • MACD — 0.576
  • バンド — 0.568

テスト取引

統計が正しく計算されるためには、EAを取引モードで実行する必要があります。これを行うには、設定でバー番号を編集し、5を0、6を1に置き換えます。さらに、「アクション」のパラメータを「アラート」の代わりに「買い」と「売り」に設定することで、取引戦略を次々と有効にする必要があります。例えば、ストキャスティクスベースの取引を確認するには、__SIGNAL_C (S_BUY stochastic) グループの「アクション」パラメータで「アラート」を「買い」に置き換え、__SIGNAL_D (S_SELL stochastic) グループでは「アラート」を「売り」に置き換えます。

3つの戦略すべてに対応する設定は、それぞれindstats-trade-stoch.set、indstats-trade-macd.set、indstats-trade-bands.setファイルにあります。

これらのパラメータセットでEAを3回実行すると、取引サマリで3つのログが生成されます。統計は終わりにあります。例えば、ストキャスティクスでは次のような行が得られます。

: Buys: 18/29 0.62 Sells: 14/22 0.64 Total: 0.63
これらの数字は実際の取引を示しています。29のうち18の買いは有益、22のうち14の売りは有益です、シグナルの全効率は0.63です。

MACDベースとボリンジャーバンドベースの戦略の結果を以下に示します。

: Buys: 29/49 0.59 Sells: 28/49 0.57 Total: 0.58
: Buys: 29/51 0.57 Sells: 34/59 0.58 Totals: 0.57
すべての戦略の値を一つのリストにまとめましょう。
  • ストキャスティクス — 0.63
  • MACD — 0.58
  • バンド — 0.57

これは、前節の理論とほぼ完全に一致していることがわかります。わずかな違いは、取引シグナルが5バー内にある場合には重複する可能性があるという事実によって説明されます。その場合、反復取引は開かれません。

当然ながら、個々の戦略ごとに取引レポートを分析することは可能です。

ストキャスティクスベースの戦略のレポート

図5 ストキャスティクスベースの戦略のレポート


MACDベースの戦略のレポート

図6 MACDベースの戦略のレポート


ボリンジャーバンドベースの戦略のレポート

図7 ボリンジャーバンドベースの戦略のレポート

すべての3つの指標からの同期シグナルに従ってエントリした場合に取引が成功する理論上の確率は、式 (4)を用いて計算されます。

P(H|ABC) = 0.63 * 0.58 * 0.57 / (0.63 * 0.58 * 0.57 + 0.37 * 0.42 * 0.43) = 0.208278 / (0.208278 + 0.066822) = 0.208278 / 0.2751 = 0.757

この状況をテストするには、3つのシグナルすべてを考慮し、ConsistentSignalNumberパラメータの値を1から3に変更する必要があります。対応する設定は、indstats-trade-all.setファイルにあります。

テスターの取引によれば、このようなシステムの実際の総合効率は0.75に等しいです。

: Buys: 4/7 0.57 Sells: 5/5 1.00 Total: 0.75
下記がテストレポートです。

3つの指標に基づく戦略の組み合わせに関するレポート

図8 3つの指標に基づく戦略の組み合わせに関するレポート

以下は、それぞれの指標による取引の表とその重ね合わせの表です。


利益($) PF N DD($)
ストキャスティクス 204 2.36 51 41
MACD 159 1.39 98 76
バンド 132 1.29 110 64
合計 68 3.18 12 30

これから分かるように、成功率はそれほど高くありませんが、より正確なエントリーにより増加します。利益率と最大減損率は少なくとも35%(場合によっては2倍以上)向上しましたが、取引数と総利益は減少しました。


終わりに

本稿では、指標シグナルに基づいて取引決断を行う確率的アプローチの最も単純な実装バージョンを検討しました。ベイズの公式を用いた理論的計算での取引の成功確率の増加が実際に得られた結果に対応することを示すために、特別なエキスパートが用いられました。

シグナル生成は離散的であるため、異なる指標シグナルが一致しないことがあります。すべての指標によって確認された共通のシグナルが指標の重ね合わせによって確認されないという状況が発生する可能性があります。この問題に対する可能な解決策の1つは、シグナル間の時間許容差の導入です。

より一般的な場合には、指標の状態(シグナルではない)に応じて取引仮説の実施の確率密度を計算することが可能です。例えば、オシレータの特定の値に基づいて特定された買われ過ぎまたは売られ過ぎの値によって、エントリの成功パーセンテージ(確率)がわかります。さらに、取引の成功確率は明らかに、選択されたストップロス及びテイクプロフィットパラメータ、ロット管理システム及びシステムの他の多くのパラメータに依存します。これらはすべて、確率論の観点から分析され、より正確であるがより複雑な取引意思決定の計算にも使用されます。

以下は添付されたファイルです。

  • indstats.mq4(及び indstats.mq5) — エキスパート
  • common-includes.zip — 共通ヘッダファイルを含むアーカイブ
  • additional-mt5-includes.zip — 追加のMetaTrader 5用のヘッダファイルを含むアーカイブ
  • instats-tester-sets.zip — 設定のためのセットファイルを含むアーカイブ

MetaQuotes Software Corp.によりロシア語から翻訳された
元の記事: https://www.mql5.com/ru/articles/3264

添付されたファイル |
indstats.mq4 (15.63 KB)
common-includes.zip (17.46 KB)
グラフィカルインターフェイスXI:レンダリングされたコントロール(ビルド14.2) グラフィカルインターフェイスXI:レンダリングされたコントロール(ビルド14.2)

ライブラリのこの新バージョンでは、すべてのコントロールが個別のOBJ_BITMAP_LABEL型のグラフィカルオブジェクトに描画されます。また、コードの最適化についても引き続き説明し、ライブラリの中核クラスの変更について説明します。

グラフィカルインターフェイスXI:ライブラリコードのリファクタリング(ビルド14.1) グラフィカルインターフェイスXI:ライブラリコードのリファクタリング(ビルド14.1)

ライブラリが大きくなるにつれて、コードをサイズを減らすために最適化が再び必要がです。本稿で説明するライブラリのバージョンはさらにオブジェクト指向になっており、コードの学習もさらに容易になります。読者は、最新の変更の詳細な記述によって、独自のニーズに基づいて独自にライブラリを開発できるでしょう。

ディープニューラルネットワーク(その1)データの準備 ディープニューラルネットワーク(その1)データの準備

この一連の記事では、取引を含んだ多くの分野で応用されているディープニューラルネットワーク(DNN)の探索を続けます。ここでは、実践的な実験によって新しい方法や概念をテストするとともにこのテーマの新しい次元を探求する予定です。シリーズの最初の記事は、DNNのデータを準備することを目的としています。

ユニバーサルEA: シンボルプロパティへのアクセス (その 8) ユニバーサルEA: シンボルプロパティへのアクセス (その 8)

このテーマの8番目のパートは、任意のトレーディングツールへアクセスする特殊なオブジェクト CSymbol クラスの説明をします。 EAで使用する場合、このクラスはEAのプログラミングを簡素化し、その関数を拡張することができ、シンボルプロパティのセットを提供します。