English Русский Deutsch
preview
MQL5での取引戦略の自動化(第1回):Profitunityシステム(ビル・ウィリアムズ著「Trading Chaos」)

MQL5での取引戦略の自動化(第1回):Profitunityシステム(ビル・ウィリアムズ著「Trading Chaos」)

MetaTrader 5トレーディング |
213 0
Allan Munene Mutiiria
Allan Munene Mutiiria

はじめに

本記事では、ビル・ウィリアムズ(英語)が開発したProfitunityシステムについて解説します。この取引戦略は、一連の主要インジケーターを活用し、市場の「混乱」から利益を得ることを目的としています。また、本システムをMetaQuotes Language 5 (MQL5)で自動化する方法も紹介します。まず、戦略の概要とその基本原則を説明し、次にMQL5による実装プロセスを解説します。特に、主要インジケーターのコーディングや、エントリー/エグジットシグナルの自動化に焦点を当てます。その後、システムをテスト・最適化し、さまざまな市場環境におけるパフォーマンスを検証します。最後に、自動取引におけるProfitunityシステムの可能性と有効性について考察します。本記事では、以下のセクションを取り上げます。

  1. Profitunityシステムの概要
  2. MQL5での戦略の実装
  3. 戦略のテストと最適化
  4. 結論

この記事を読み終える頃には、MQL5を活用してProfitunityシステムを自動化する方法を理解できるでしょう。主要インジケーターの実装からパフォーマンス最適化までの流れを学ぶことで、取引戦略を強化し、市場の「混乱」を活かしてより高い取引成果を狙うためのスキルが身につきます。それでは、さっそく始めましょう。


Profitunityシステムの概要

ビル・ウィリアムズが考案したProfitunityシステムは、市場の混沌とした動きを理解し、それに対応するための特殊なインジケーター群を活用します。この戦略は、トレンドフォロー型のインジケーターとモメンタムインジケーターを組み合わせることで、柔軟かつ高い応答性を持つ取引手法を実現します。Profitunityシステムの主な目的は、トレンドの反転や市場の加速を識別し、高確率の取引チャンスを見つけることです。本戦略で使用される主要なインジケーターは以下の4つです。

  • Fractals(フラクタル)
  • Alligator(アリゲーター)
  • Awesome Oscillator (AO)
  • Accelerator Oscillator (AC)

これらのインジケーターは相互に連携しながら、市場環境に関する重要な情報を提供し、エントリーおよびエグジットのシグナルを示します。次に、それぞれのインジケーターの詳細な設定と役割について詳しく見ていきましょう。

インジケーターの設定

フラクタルインジケーターは、市場の反転ポイントを特定するためのツールです。フラクタルは、5本の連続したバーのうち、中央のバーが最も高い(または低い)場合に形成されます。これは、新しいトレンドの始まりや価格の反転の可能性を示唆し、ローカルの高値・安値を特定することで、トレンド変化の早期シグナルとして機能します。設定に関しては、フラクタルのデフォルトの期間は2または5です。これは、1本のバーを中心に、左右それぞれ2本のバーが「より低い(フラクタルダウン)」または「より高い(フラクタルアップ)」パターンを形成しているかをチェックすることを意味します。以下のチャートに、フラクタルの具体的な形状を示します。

フラクタル

アリゲーターインジケーターは、顎、歯、唇と呼ばれる 3 つの平滑移動平均線の組み合わせであり、市場のトレンドを判断するために連携して機能します。これらの線間の相互作用は、市場がトレンドにあるか、または統合されているかを認識するのに役立ちます。線が広がり始めると、トレンドの兆候となり、収束すると、市場が統合の段階にあることを示唆します。

設定:

  • 顎(青線):13期間、8バーで平滑化
  • 歯(赤線):8期間、5バーで平滑化
  • 唇(緑の線):5期間、3バーで平滑化

このインジケーターを活用することで、トレンドの方向とタイミングを把握し、適切なエントリーやエグジットの判断をおこなうことが可能になります。以下のチャートに、設定を適用したアリゲーターインジケーターの様子を示します。

アリゲーター

Awesome Oscillator (AO)は、モメンタム(勢い)を測定するインジケーターです。中央値の34期間単純移動平均(SMA)と5期間SMAの差を計算し、その値をヒストグラムとしてプロットすることで、トレンドの強さと方向を把握するのに役立ちます。AOの設定はデフォルト値で使用されます。

AOは主に、市場の強気または弱気の勢いを識別し、トレンドの転換ポイントを見つけるために使用されます。ゼロラインより上のヒストグラムは上昇(強気)の勢いを示し、ゼロラインより下のヒストグラムは下降(弱気)の勢いを示します。

Accelerator Oscillator (AC)はAOインジケーターから派生しており、市場の勢いの加速を測定します。市場の勢いが加速しているか減速しているかについての洞察を提供し、トレンドの変化が完全に現れる前にそれを検出するために不可欠です。ACはゼロラインを中心に振動し、緑(正)または赤(負)のゾーン内を移動します。その設定もデフォルト値で使用されます。

ACインジケーターは、AOインジケーターと組み合わせて使用され、市場の強さと勢いの変化を確認するためのツールです。このインジケーターを使用することで、取引に入る前に市場が一方向に強く動いていることを確認することができます。次に、システムで使用されるエントリー条件とエグジット条件を見てみましょう。AOとACのインジケーターがどのように組み合わさるか、以下の図で確認できます。

AOとAC

エントリーおよびエグジットの条件

このシステムでは、フラクタル、アリゲーター、Accelerator Oscillator (AC)、Awesome Oscillator (AO)からの連続シグナルに基づいて、取引を開始および終了するための特定の条件を使用します。これらのシグナルは連携して機能し、市場が方向性を強く確認した時にのみ取引を開始することで、誤ったシグナルのリスクを軽減します。

買いエントリー条件

  1. フラクタルシグナル:フラクタルダウンシグナルは、価格が一連の低い高値を形成しており、価格が上昇に転じる可能性を示唆する時に発生します。
  2. アリゲーターラインの内訳:アリゲーターの青い線(顎線)が下から上に突破し、上昇トレンドの始まりを示します。
  3. Accelerator Oscillator (AC)の確認:ACが緑のゾーンにあり、強気の勢いを示し、トレンドの強さを支持しています。
  4. Awesome Oscillator (AO)の確認:AOヒストグラムがゼロラインを下から上に超え、上昇の勢いをさらに確認します。

買い条件

AOインジケーターのヒストグラムがゼロラインを下から上へ交差し、強気の勢いの上昇を確認した後、買いエントリーがトリガーされます。これは、強い上昇トレンドが形成されつつあることを示しており、市場買いポジションを開くポイントとなります。以下は、 MetaTrader 5チャートの買いシグナルの例です。

MT5買いシグナル

売りエントリー条件

  1. フラクタルシグナル:フラクタルアップシグナルは、価格が一連のより高い安値を形成し、価格が下向きに反転する可能性を示唆する時に発生します。
  2. アリゲーターラインの内訳:アリゲーターの青い線(顎線)が上から下に突破し、下降トレンドの始まりを示します。
  3. Accelerator Oscillator (AC)の確認:ACが赤のゾーンにあり、強い弱気の勢いを確認し、下落が続く可能性が高いことを示しています。
  4. Awesome Oscillator (AO)の確認:AOヒストグラムが上から下にゼロラインを下回り、弱気トレンドを示します。

売り条件

AOヒストグラムが上からゼロラインを下回り、下降の勢いが確認されると、売りエントリーがトリガーされます。これは、市場が引き続き下落する可能性が高いことを示しており、市場売りポジションを開くポイントとなります。

エグジットまたは反転の条件

  1. アリゲーターラインの反転:アリゲーターの緑の線(唇)の反転が発生すると、現在のトレンドの終了を示唆します。唇の方向が反転することで、価格が反転または統合している可能性があることを示します。
  2. Accelerator Oscillator (AC)の反転:ACが緑のゾーンから赤のゾーン(またはその逆)に交差すると、勢いの変化を示し、市場の勢いが変化しており、現在のトレンドが終わりに近づいていることを示す初期の兆候となります。
  3. Awesome Oscillator (AO)の反転:AOヒストグラムがゼロラインを反対方向に横切ることで、トレンドの反転が発生する可能性が高いことがさらに確認されます。

エグジット条件

上記の終了条件のいずれかまたはすべてを使用することができますが、このケースでは、AOインジケーターのヒストグラムが反対のゾーンに交差し、市場の勢いの変化を示しているときにポジションを終了することを選択します。

前述のインジケーターの組み合わせを利用することで、Profitunityシステムは市場の反転と強いトレンドの機会を特定するための強力なアプローチを提供します。次のセクションでは、これらのエントリー条件とエグジット条件をMQL5で実装し、この戦略を完全に自動化する方法について説明します。


MQL5での戦略の実装

ビル・ウィリアムズのProfitunity取引戦略に関するすべての理論を学んだ後、その理論を自動化し、MetaQuotes Language 5 (MQL5)でMetaTrader5用のエキスパートアドバイザー(EA)を作成します。

EAを作成するには、MetaTrader5端末で[ツール]タブをクリックし、[MetaQuotes言語エディタ]を選択するか、キーボードのF4を押します。または、ツールバーのIDE(統合開発環境)アイコンをクリックすることもできます。これにより、MetaQuotes言語エディタ環境が開き、取引ロボット、テクニカルインジケーター、スクリプト、関数のライブラリを作成できるようになります。

メタエディターを開く

MetaEditorを開いたら、ツールバーの[ファイル]タブで[新しいファイル]を選択するか、CTRL+Nキーを押して新規ドキュメントを開きます。または、[ツール]タブの新規アイコンをクリックすることもできます。MQLウィザードのポップアップが表示されます。

新しいEAを作成

ウィザードが表示されたら、[EA(テンプレート)]を選択し、[次へ]をクリックします。

MQLウィザード

EAの一般プロパティで、[名前]フィールドにEAのファイル名を入力します。フォルダが存在しない場合にフォルダを指定または作成するには、EA名の前にバックスラッシュを使用することに注意してください。例えば、ここではデフォルトで「Experts\」となっています。つまり、私たちのEAはExpertsフォルダに作成され、そこで見つけることができます。他のフィールドはごく簡単ですが、ウィザードの一番下にあるリンクから、正確な手順を知ることができます。

新しいEA名

希望するEAファイル名を入力した後、[次へ]をクリックし、[完了]をクリックします。ここまでくれば、あとはコードを書いて戦略をプログラムするだけです。

まず、EAに関するメタデータを定義することから始めます。これには、EA名、著作権情報、MetaQuotesWebサイトへのリンクが含まれます。EAのバージョンも指定し、1.00とします。

//+------------------------------------------------------------------+
//|              1. PROFITUNITY (TRADING CHAOS BY BILL WILLIAMS).mq5 |
//|      Copyright 2024, ALLAN MUNENE MUTIIRIA. #@Forex Algo-Trader. |
//|                                     https://forexalgo-trader.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, ALLAN MUNENE MUTIIRIA. #@Forex Algo-Trader"
#property link      "https://forexalgo-trader.com"
#property description "1. PROFITUNITY (TRADING CHAOS BY BILL WILLIAMS)"
#property version   "1.00"

これにより、プログラムをロードするときにシステムメタデータが表示されます。次に、プログラム内で使用するグローバル変数をいくつか追加します。まず、ソースコードの先頭で#includeを使用して、取引インスタンスをインクルードします。これにより、CTradeクラスにアクセスできるようになります。これを使用して、取引オブジェクトを作成します。これは取引を開始するために必要なので、非常に重要です。

#include <Trade/Trade.mqh>
CTrade obj_Trade;

プリプロセッサは、#include<Trade/Trade.mqh>行をファイルTrade.mqhの内容に置き換えます。角括弧は、Trade.mqhファイルが標準ディレクトリ(通常、terminal_installation_directory\MQL5\Include)から取得されることを示します。カレントディレクトリは検索に含まれません。この行はプログラム中のどこにでも配置できますが、通常は、より良いコード構造と参照を容易にするために、すべてのインクルージョンはソースコードの先頭に置かれます。CTradeクラスのobj_Tradeオブジェクトを宣言すると、MQL5開発者のおかげで、そのクラスに含まれるメソッドに簡単にアクセスできるようになります。

CTRADEクラス

その後、取引システムで使用するいくつかの重要なインジケーターハンドルを宣言する必要があります。

int handle_Fractals = INVALID_HANDLE; //--- Initialize fractals indicator handle with an invalid handle value
int handle_Alligator = INVALID_HANDLE; //--- Initialize alligator indicator handle with an invalid handle value
int handle_AO = INVALID_HANDLE; //--- Initialize Awesome Oscillator (AO) handle with an invalid handle value
int handle_AC = INVALID_HANDLE; //--- Initialize Accelerator Oscillator (AC) handle with an invalid handle value

ここでは、プログラム内の各テクニカルインジケーターのハンドルを保持するための初期変数を設定します。具体的には、4つの整数型変数(handle_Fractals、handle_Alligator、handle_AO、handle_AC)をINVALID_HANDLE値で初期化します。

これらの各ハンドルは、コード全体でそれぞれのインジケーターにアクセスするための参照として機能します。初期値INVALID_HANDLEを割り当てることで、コードの後半で適切な初期化がおこなわれるまで、各ハンドル変数が無効な状態を明確に示すようになります。この設定により、初期化されていないハンドルの使用によるエラーが防止され、初期化プロセス中にインジケーターの読み込みに失敗したかどうかを検出できるようになります。

個々のインジケーターについて要約すると、次のようになります。

  • handle_Fractalsは、フラクタルインジケーターのハンドルを格納する
  • handle_Alligatorはアリゲーターインジケーターのハンドルを格納する
  • handle_AOは、Awesome Oscillatorのハンドルを格納する
  • handle_ACはAccelerator Oscillator (AC)のハンドルを格納する

次に、このEAで使用されるインジケーターのデータを格納および処理するために必要な配列と定数を定義して初期化する必要があります。これらのデータは、初期化されたインジケーターハンドルから取得されます。参照しやすくシンプルに整理するために、順番に実行します。

double fractals_up[]; //--- Array to store values for upward fractals
double fractals_down[]; //--- Array to store values for downward fractals

double alligator_jaws[]; //--- Array to store values for Alligator's Jaw line
double alligator_teeth[]; //--- Array to store values for Alligator's Teeth line
double alligator_lips[]; //--- Array to store values for Alligator's Lips line

double ao_values[]; //--- Array to store values of the Awesome Oscillator (AO)

double ac_color[]; //--- Array to store color status of the Accelerator Oscillator (AC)
#define AC_COLOR_UP 0 //--- Define constant for upward AC color state
#define AC_COLOR_DOWN 1 //--- Define constant for downward AC color state

まず、上向きフラクタルと下向きフラクタルの値をそれぞれ格納する2つの配列(fractals_upとfractals_down)を作成します。これらの配列により、特定のフラクタルポイントを追跡できるようになります。これは、重要な価格の反転やパターンを識別するのに有用です。

次に、アリゲーターインジケーターのさまざまな線の値を格納するために、alligator_jaws、alligator_teeth、alligator_lipsの3つの配列を設定します。これらの値を別々の配列に保持することで、各アリゲーターラインの状態を効率的に追跡し、取引シグナルの相互参照に使用することができます。

次に、Awesome Oscillator (AO)の値を格納するためのao_values配列を定義します。AOは市場の勢いと傾向を識別するのに役立ち、これらの値を保存することで、時間の経過に伴う変化を分析し、それを取引条件に適用することができます。

最後に、Accelerator Oscillator (AC)の色の状態をキャプチャするためのac_color配列を定義します。この配列には、ACの上方向または下方向の動きに関する情報が保持され、色の状態として保存されます。これを容易にするために、2つの定数AC_COLOR_UP(0に設定)およびAC_COLOR_DOWN(1に設定)を定義します。これらの定数はACの色の状態を表し、緑(上向き)は勢いの増加を示し、赤(下向き)は減速傾向を示します。この設定により、後で取引シグナルのAC状態を確認するときのロジックが簡素化されます。

フラクタル以外の他のインジケーターの値も簡単に直接保存できることにお気づきかもしれません。これは、その値がすべてのバーですぐに利用できるからです。ただし、フラクタルに関しては、現在のバーから少なくとも3バー離れた特定のスイングポイントで形成されます。したがって、条件付きで形成されるフラクタルバーをそのまま取得することはできません。したがって、以前のフラクタル値とその方向を追跡するためのロジックが必要です。私たちが採用するロジックは次のとおりです。

double lastFractal_value = 0.0; //--- Variable to store the value of the last detected fractal
enum fractal_direction {FRACTAL_UP, FRACTAL_DOWN, FRACTAL_NEUTRAL}; //--- Enum for fractal direction states
fractal_direction lastFractal_direction = FRACTAL_NEUTRAL; //--- Variable to store the direction of the last fractal

ここでは、取引分析で検出された最新のフラクタルのデータを格納および管理するための変数と列挙体を定義します。まず、lastFractal_value変数を宣言し、0.0に初期化します。この変数には、チャート上で最後に検出されたフラクタルの数値が格納されます。この値を追跡することで、現在の価格と比較したり、潜在的な取引シグナルのフラクタル形成を分析したりできます。

次に、FRACTAL_UP、FRACTAL_DOWN、FRACTAL_NEUTRALの3つの状態を持つ列挙体「fractal_direction」を定義します。これらの状態は最後のフラクタルの方向を表します。

  • FRACTAL_UPは上向きのフラクタルを示し、潜在的な弱気相場を示唆
  • FRACTAL_DOWNは下向きのフラクタルを示し、潜在的な強気相場を示唆
  • FRACTAL_NEUTRALは、特定のフラクタル方向が確認されていない状態を表す

最後に、fractal_direction型の変数lastFractal_directionを宣言し、FRACTAL_NEUTRALに初期化します。この変数は最後に検出されたフラクタルの方向を保持し、最新のフラクタルデータに基づいて取引ロジック内で方向評価をおこなうことができます。

この基盤をもとに、実際のコード処理ロジックに進むことができます。インジケーターを初期化する必要があるため、プログラムが初期化されるたびに呼び出され実行されるOnInitイベントハンドラに直接進みます。
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){
   //---

   //---
   return(INIT_SUCCEEDED); //--- Return successful initialization status
}

これは、プログラムの制御ロジックを初期化するために使用するデフォルトの初期化イベントハンドラです。次に、インジケーターを初期化してチャートに添付し、データの取得と取引の決定に使用できるようにする必要があります。まず、フラクタルインジケーターを以下のように初期化します。

   handle_Fractals = iFractals(_Symbol,_Period); //--- Initialize the fractals indicator handle
   if (handle_Fractals == INVALID_HANDLE){ //--- Check if the fractals indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE FRACTALS INDICATOR. REVERTING NOW!"); //--- Print error if fractals initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }

ここでは、iFractals関数を呼び出してhandle_Fractals変数を初期化します。この関数は、指定された銘柄(_Symbol)と現在のチャート期間(_Period)に適用されるフラクタルインジケーターのハンドルを作成します。iFractalsの戻り値にhandle_Fractalsを設定することで、インジケーターデータへのアクセスが有効になり、後で戦略のフラクタル形成を分析するために使用できるようになります。

フラクタルインジケーターの初期化を試みた後、handle_FractalsがINVALID_HANDLEに等しいかどうかをチェックして成功したかどうかを確認します。INVALID_HANDLE値は、インジケーターを初期化できなかったことを示します。これは、システムリソースの不足やパラメータの誤りなど、さまざまな理由で発生する可能性があります。

初期化に失敗した場合は、Print関数を使用してエラーメッセージ「ERROR:UNABLE TO INITIALIZE THE FRACTALS INDICATOR.REVERTING NOW!」と操作ログに書き込みます。このメッセージは問題を明確に通知するものとなり、トラブルシューティングが容易になります。次に、初期化プロセスが正常に完了できなかったことを通知して、INIT_FAILEDを返してOnInit関数を終了します。このチェックは、EAが不完全なセットアップで続行して実行中にエラーが発生しないようにするのに役立ちます。アリゲーターインジケーターの初期化についても同じことをおこないます。

   handle_Alligator = iAlligator(_Symbol,_Period,13,8,8,5,5,3,MODE_SMMA,PRICE_MEDIAN); //--- Initialize the alligator indicator with specific settings
   if (handle_Alligator == INVALID_HANDLE){ //--- Check if the alligator indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE ALLIGATOR INDICATOR. REVERTING NOW!"); //--- Print error if alligator initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }

iAlligator関数を呼び出して、handle_Alligator変数を初期化します。アリゲーターインジケーターには、市場のトレンドに反応する3つの線(顎、歯、唇)を定義するためのいくつかのパラメータが必要です。期間は顎は「13」、歯は「8」、唇は「5」として設定します。さらに、各線に「8」、「5」、「3」のシフト値を定義し、計算方法をMODE_SMMA(平滑移動平均)に設定し、価格タイプとしてPRICE_MEDIANを使用します。

アリゲーターインジケーターの初期化を試みた後、handle_Alligatorに有効なハンドルがあるかどうかを確認します。INVALID_HANDLEと等しい場合は、初期化プロセスが失敗したことを示します。これは、リソース不足またはパラメータの誤りが原因で発生し、アリゲーターインジケーターが正しく機能しない可能性があります。

初期化に失敗した場合は、Print関数を呼び出してエラーメッセージ「ERROR:UNABLE TO INITIALIZE THE ALLIGATOR INDICATOR.REVERTINGNOW!」を表示します。このメッセージは問題を警告するのに役立ち、診断と解決が容易になります。メッセージを出力した後、INIT_FAILEDを返します。これはOnInit関数を終了し、初期化が正常に完了しなかったことを示します。 

同様のアプローチを使用して、AOおよびACインジケーターを次のように初期化します。

   handle_AO = iAO(_Symbol,_Period); //--- Initialize the Awesome Oscillator (AO) indicator handle
   if (handle_AO == INVALID_HANDLE){ //--- Check if AO indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE AO INDICATOR. REVERTING NOW!"); //--- Print error if AO initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   handle_AC = iAC(_Symbol,_Period); //--- Initialize the Accelerator Oscillator (AC) indicator handle
   if (handle_AC == INVALID_HANDLE){ //--- Check if AC indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE AC INDICATOR. REVERTING NOW!"); //--- Print error if AC initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }

すべてのインジケーターが正常に初期化されたら、プログラムがロードされたときにそれらをチャートに自動的に追加できます。これを実現するために、次のロジックを使用します。

   if (!ChartIndicatorAdd(0,0,handle_Fractals)){ //--- Add the fractals indicator to the main chart window and check for success
      Print("ERROR: UNABLE TO ADD THE FRACTALS INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if fractals addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }

ここでは、ChartIndicatorAdd関数を使用して、フラクタルインジケーターをメインチャートウィンドウに追加します。チャートID(現在のチャートを示す)として「0」を渡し、メインチャートウィンドウをターゲットとするウィンドウIDとして「0」を指定します。フラクタルインジケーターハンドルを格納するために以前に初期化したhandle_Fractals変数は、この特定のインジケーターを追加するために渡されます。

ChartIndicatorAdd関数を呼び出した後、関数呼び出しが成功したかどうかを確認します。false(「!」で表される)を返す場合、フラクタルインジケーターをチャートに追加できなかったことを示します。ここでの失敗は、チャート制限またはリソース不足が原因で発生する可能性があります。この場合、警告のために、Printを使用してエラーメッセージ「ERROR:UNABLE TO ADD THE FRACTALS INDICATOR TO CHART.REVERTINGNOW!」を表示します。このメッセージにより、デバッグ中に問題の原因を迅速に特定できるようになります。

追加が失敗した場合は、INIT_FAILEDを返してOnInit関数を失敗ステータスで終了し、チャートにフラクタルインジケーターがない場合にはEAが実行されないようにします。これにより、インジケーターの視覚的な可用性を確認することで、後で実行エラーを防ぐことができます。以下のように、メインウィンドウにもアリゲーターインジケーターが表示されるため、同様のロジックを使用してアリゲーターインジケーターを追加します。

   if (!ChartIndicatorAdd(0,0,handle_Alligator)){ //--- Add the alligator indicator to the main chart window and check for success
      Print("ERROR: UNABLE TO ADD THE ALLIGATOR INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if alligator addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }

他のインジケーターを追加するには、同様のアプローチが使用されますが、次のようにインジケーターごとにそれぞれ新しいサブウィンドウを作成するため、サブウィンドウが変更される点のみが異なります。

   if (!ChartIndicatorAdd(0,1,handle_AO)){ //--- Add the AO indicator to a separate subwindow and check for success
      Print("ERROR: UNABLE TO ADD THE AO INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if AO addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   if (!ChartIndicatorAdd(0,2,handle_AC)){ //--- Add the AC indicator to a separate subwindow and check for success
      Print("ERROR: UNABLE TO ADD THE AC INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if AC addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }

Awesome Oscillator (AO)インジケーターとAcceleratorOscillator(AC)インジケーターをチャート上の別のサブウィンドウに追加し、それぞれ専用のビューが表示されるようにします。これを実現するには、各インジケーターに対してChartIndicatorAdd関数を使用します。チャートID(現在のチャートを示す)に「0」を指定し、個別のウィンドウIDを使用します。AOインジケーターの場合は「1」、ACインジケーターの場合は「2」で、それぞれが固有のサブウィンドウに表示されるように指示します。ここでの番号付けは、すべてのインジケーターがウィンドウ上に配置される必要があるため重要であり、サブウィンドウのインデックスを適切に追跡する必要があります。

次に、追加が成功したかどうかを個別に確認します。ChartIndicatorAddがAOまたはACインジケーターのいずれかに対してfalseを返した場合、追加プロセスが失敗したことが示されます。失敗した場合は、どのインジケーターの読み込みに失敗したかを明確にするために、Printでエラーメッセージを出力します。たとえば、AOインジケーターを追加できない場合は、「ERROR:UNABLE TO ADD THE AO INDICATOR TO CHART.REVERTINGNOW!」を表示します。同様に、ACインジケーターの追加が失敗した場合もエラーメッセージを出力します。

いずれかのインジケーターの追加が失敗した場合は、直ちにINIT_FAILEDを返し、OnInit関数を終了してそれ以上の実行を防止します。すべてが正常であることを確認するために、インジケーターハンドルを操作ログに出力できます。

   Print("HANDLE ID FRACTALS = ",handle_Fractals); //--- Print the handle ID for fractals
   Print("HANDLE ID ALLIGATOR = ",handle_Alligator); //--- Print the handle ID for alligator
   Print("HANDLE ID AO = ",handle_AO); //--- Print the handle ID for AO
   Print("HANDLE ID AC = ",handle_AC); //--- Print the handle ID for AC

プログラムを実行すると、次の初期化データが取得されます。

インジケーターはデータを処理する

画像から、ハンドルIDは10から始まり、順番に13まで続くことがわかります。ハンドルIDは、EAのライフサイクル全体を通じて各インジケーターを参照できるため、MQL5では非常に重要です。CopyBufferのような関数がインジケーターから値を取得する場合、正しいデータにアクセスするためにこれらのハンドルに依存します。ここで、整数は初期化された各インジケーターの特定の識別子を表します。各IDはMQL5環境内で一意の「ポインタ」として機能し、各ハンドルを指定されたインジケーターにリンクします。これにより、EAはメモリからどのインジケーターデータを取得するかを把握し、インジケーターベースのタスクの効率的な実行と明確な構成をサポートします。

そこから、必要なのはデータホルダーを時系列として設定することだけです。

   ArraySetAsSeries(fractals_up,true); //--- Set the fractals_up array as a time series
   ArraySetAsSeries(fractals_down,true); //--- Set the fractals_down array as a time series
   
   ArraySetAsSeries(alligator_jaws,true); //--- Set the alligator_jaws array as a time series
   ArraySetAsSeries(alligator_teeth,true); //--- Set the alligator_teeth array as a time series
   ArraySetAsSeries(alligator_lips,true); //--- Set the alligator_lips array as a time series
   
   ArraySetAsSeries(ao_values,true); //--- Set the ao_values array as a time series
   
   ArraySetAsSeries(ac_color,true); //--- Set the ac_color array as a time series

ここでは、各配列を時系列として動作するように設定します。つまり、各配列内のデータは最新の値から最も古い値の順に整理されます。これをおこなうには、ArraySetAsSeries関数を各配列に適用し、2番目の引数としてtrueを渡します。この設定により、最新のデータポイントが常にインデックス0に表示されるようになります。これは、リアルタイムの意思決定に最新の値へのアクセスが不可欠な取引アプリケーションで特に役立ちます。

まず、fractals_up配列とfractals_down配列を時系列として設定し、最新の上向きフラクタル値と下向きフラクタル値を効率的に追跡できるようにします。同様に、この構成を、アリゲーターインジケーターの3本の線を表すalligator_jaws、alligator_teeth、alligator_lips配列に適用します。これにより、それぞれの線の最新値にリアルタイムでアクセスできるようになり、市場動向の変化をより簡単に検出できるようになります。

Awesome Oscillator (AO)のデータを格納するao_values配列も同様に設定します。これを時系列として設定することで、最新のオシレーター値が常に計算に利用できるようになります。最後に、この構造を、Accelerator Oscillator (AC)の色の状態を追跡するac_color配列に適用し、最新の色の状態にすぐにアクセスできるようにします。スムーズでクリーンな初期化を保証する完全な初期化コードスニペットは次のとおりです。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){
   //---
   
   handle_Fractals = iFractals(_Symbol,_Period); //--- Initialize the fractals indicator handle
   if (handle_Fractals == INVALID_HANDLE){ //--- Check if the fractals indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE FRACTALS INDICATOR. REVERTING NOW!"); //--- Print error if fractals initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   handle_Alligator = iAlligator(_Symbol,_Period,13,8,8,5,5,3,MODE_SMMA,PRICE_MEDIAN); //--- Initialize the alligator indicator with specific settings
   if (handle_Alligator == INVALID_HANDLE){ //--- Check if the alligator indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE ALLIGATOR INDICATOR. REVERTING NOW!"); //--- Print error if alligator initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   handle_AO = iAO(_Symbol,_Period); //--- Initialize the Awesome Oscillator (AO) indicator handle
   if (handle_AO == INVALID_HANDLE){ //--- Check if AO indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE AO INDICATOR. REVERTING NOW!"); //--- Print error if AO initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   handle_AC = iAC(_Symbol,_Period); //--- Initialize the Accelerator Oscillator (AC) indicator handle
   if (handle_AC == INVALID_HANDLE){ //--- Check if AC indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE AC INDICATOR. REVERTING NOW!"); //--- Print error if AC initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   
   if (!ChartIndicatorAdd(0,0,handle_Fractals)){ //--- Add the fractals indicator to the main chart window and check for success
      Print("ERROR: UNABLE TO ADD THE FRACTALS INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if fractals addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   if (!ChartIndicatorAdd(0,0,handle_Alligator)){ //--- Add the alligator indicator to the main chart window and check for success
      Print("ERROR: UNABLE TO ADD THE ALLIGATOR INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if alligator addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   if (!ChartIndicatorAdd(0,1,handle_AO)){ //--- Add the AO indicator to a separate subwindow and check for success
      Print("ERROR: UNABLE TO ADD THE AO INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if AO addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   if (!ChartIndicatorAdd(0,2,handle_AC)){ //--- Add the AC indicator to a separate subwindow and check for success
      Print("ERROR: UNABLE TO ADD THE AC INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if AC addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   
   Print("HANDLE ID FRACTALS = ",handle_Fractals); //--- Print the handle ID for fractals
   Print("HANDLE ID ALLIGATOR = ",handle_Alligator); //--- Print the handle ID for alligator
   Print("HANDLE ID AO = ",handle_AO); //--- Print the handle ID for AO
   Print("HANDLE ID AC = ",handle_AC); //--- Print the handle ID for AC

   ArraySetAsSeries(fractals_up,true); //--- Set the fractals_up array as a time series
   ArraySetAsSeries(fractals_down,true); //--- Set the fractals_down array as a time series
   
   ArraySetAsSeries(alligator_jaws,true); //--- Set the alligator_jaws array as a time series
   ArraySetAsSeries(alligator_teeth,true); //--- Set the alligator_teeth array as a time series
   ArraySetAsSeries(alligator_lips,true); //--- Set the alligator_lips array as a time series
   
   ArraySetAsSeries(ao_values,true); //--- Set the ao_values array as a time series
   
   ArraySetAsSeries(ac_color,true); //--- Set the ac_color array as a time series
   
   //---
   return(INIT_SUCCEEDED); //--- Return successful initialization status
}

次に、制御ロジックを格納するOnTickイベントハンドラに進みます。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){
//---
}
これは、制御ロジックのベースとして使用するデフォルトのティックイベントハンドラです。次に、さらなる分析のためにインジケーターハンドルからデータ値を取得する必要があります。
   if (CopyBuffer(handle_Fractals,0,2,3,fractals_up) < 3){ //--- Copy upward fractals data; check if copying is successful
      Print("ERROR: UNABLE TO COPY THE FRACTALS UP DATA. REVERTING!"); //--- Print error message if failed
      return;
   }
   if (CopyBuffer(handle_Fractals,1,2,3,fractals_down) < 3){ //--- Copy downward fractals data; check if copying is successful
      Print("ERROR: UNABLE TO COPY THE FRACTALS DOWN DATA. REVERTING!"); //--- Print error message if failed
      return;
   }

ここでは、handle_Fractalsインジケーターのfractals_upおよびfractals_downバッファからデータをそれぞれの配列にコピーしています。インジケーターハンドルからデータを取得するには、CopyBuffer関数を使用します。具体的には、上向きフラクタルと下向きフラクタルの両方について、3番目に新しいバー(インデックス2)から始まる3つのデータポイントのコピーを試みます。

まず、関数が3未満の値を返すかどうかを確認します。これは、3未満の値がfractals_up配列に正常にコピーされたことを示します。このような場合は、エラーメッセージ「ERROR:UNABLE TO COPY THE FRACTALS UP DATA.REVERTING!」を表示して、不完全なデータによるそれ以上の処理を防ぐために、関数を終了します。

同様に、同じCopyBuffer関数を使用して、下向きのフラクタルデータをfractals_down配列にコピーしようとします。再度、コピーが失敗した場合(3つ未満の値が返された場合)、対応するエラーメッセージ「ERROR:UNABLE TO COPY THE FRACTALS DOWN DATA.REVERTING!」を表示して、さらなる問題を回避するために、この関数を終了します。このアプローチにより、プログラムは無効または不完全なデータで処理を進めず、取引ロジックの整合性を維持できます。正しい数の値がコピーされたことを確認することで、市場の反転ポイントを検出するために重要なフラクタルの分析における潜在的なエラーを防ぐことができます。

ただし、インジケーターバッファ番号が0と1で異なることにお気付かもしれません。これらは、インジケーター値の実際のマッピングバッファを表すため、注意を払う必要がある重要なインデックスです。特定のインデックスを使用する理由を理解するための図を示します。

バッファインデックス

画像から、上向きのフラクタルが最初でインデックス0であり、下向きのフラクタルが2番目でインデックス1であることがわかります。同じロジックを使用して、アリゲーターの線をマッピングします。

   if (CopyBuffer(handle_Alligator,0,0,3,alligator_jaws) < 3){ //--- Copy Alligator's Jaw data
      Print("ERROR: UNABLE TO COPY THE ALLIGATOR JAWS DATA. REVERTING!");
      return;
   }
   if (CopyBuffer(handle_Alligator,1,0,3,alligator_teeth) < 3){ //--- Copy Alligator's Teeth data
      Print("ERROR: UNABLE TO COPY THE ALLIGATOR TEETH DATA. REVERTING!");
      return;
   }
   if (CopyBuffer(handle_Alligator,2,0,3,alligator_lips) < 3){ //--- Copy Alligator's Lips data
      Print("ERROR: UNABLE TO COPY THE ALLIGATOR LIPS DATA. REVERTING!");
      return;
   }

ここでは、バッファが3行に分かれているため、バッファインデックスが0から1を経て2まで続いていることがわかります。AOインジケーターの場合のように、バッファが1つしかない場合は、以下のように価格のバッファインデックス0のみになります。

   if (CopyBuffer(handle_AO,0,0,3,ao_values) < 3){ //--- Copy AO data
      Print("ERROR: UNABLE TO COPY THE AO DATA. REVERTING!");
      return;
   }

ACインジケーターの値に興味がある場合、同じことがACインジケーターにも当てはまります。ただし、形成されるヒストグラムの色だけを知る必要があります。これらは同じバッファ番号ロジックを使用して取得できますが、この場合、カラーバッファは主にデータウィンドウ内の次の使用できないバッファインデックスにマップされます。したがって、この場合、次のとおり0+1=1となります。

   if (CopyBuffer(handle_AC,1,0,3,ac_color) < 3){ //--- Copy AC color data
      Print("ERROR: UNABLE TO COPY THE AC COLOR DATA. REVERTING!");
      return;
   }

実際にカラーバッファを取得するには、インジケーターのプロパティウィンドウを開くだけで、パラメータタブにカラーインデックスが表示されます。

カラーバッファインデックス

データを取得して保存した後、それを使用して取引の決定をおこなうことができます。リソースを節約するために、生成されるすべてのティックではなく、すべてのバーでチェックを実行します。したがって、新しいバーの形成を検出するためのロジックが必要です。

if (isNewBar()){ //--- Check if a new bar has formed

//---

}

ここでは、以下のコードスニペットを持つカスタム関数を利用します。

//+------------------------------------------------------------------+
//|   IS NEW BAR FUNCTION                                            |
//+------------------------------------------------------------------+
bool isNewBar(){ 
   static int prevBars = 0; //--- Store previous bar count
   int currBars = iBars(_Symbol,_Period); //--- Get current bar count for the symbol and period
   if (prevBars == currBars) return (false); //--- If bars haven't changed, return false
   prevBars = currBars; //--- Update previous bar count
   return (true); //--- Return true if new bar is detected
}

ここでは、チャートに新しいバーが表示されたかどうかをチェックするブール関数isNewBarを定義します。これは、取引条件を更新または再計算するために不可欠な、新しいローソク足またはバーが形成されたタイミングを検出するのに役立ちます。まず、整数型のstatic変数prevBarsを宣言し、それを0に初期化します。キーワード「static」により、prevBarsの値は関数が呼び出されるたびにリセットされるのではなく、関数の複数の呼び出しに渡って保持されます。これにより、前の関数呼び出しからのバーの数を保存できます。

次に、ローカル整数変数currBarsを定義し、組み込みのiBars関数を使用して、選択した銘柄(_Symbol)と期間(_Period)の現在のバーの数を取得します。この関数は、指定された時間枠で利用可能なバーの合計数をカウントし、それをcurrBarsに保存します。

次に、prevBarsとcurrBarsを比較します。2つの値が等しい場合は、関数が最後に呼び出されてから新しいバーが形成されていないことを意味するため、新しいバーが検出されなかったことを示すためにfalseを返します。バーの数が変更された場合(つまり、新しいバーが形成された場合)、条件は満たされず、新しい値を追跡するためにprevBarsが現在のバー数(currBars)で更新されます。最後に、新しいバーが検出されたことを通知するためにtrueを返します。

この関数内では、fractals_up配列とfractals_down配列に保存されているデータに基づいて、最後に検出されたフラクタルの値と方向をチェックして更新することで、フラクタルデータを決定して保存できます。

const int index_fractal = 0;
if (fractals_up[index_fractal] != EMPTY_VALUE){ //--- Detect upward fractal presence
   lastFractal_value = fractals_up[index_fractal]; //--- Store fractal value
   lastFractal_direction = FRACTAL_UP; //--- Set last fractal direction as up
}
if (fractals_down[index_fractal] != EMPTY_VALUE){ //--- Detect downward fractal presence
   lastFractal_value = fractals_down[index_fractal];
   lastFractal_direction = FRACTAL_DOWN;
}

まず、整数型の定数「index_fractal」を定義し、それを0に設定します。この定数は、チェックする現在のフラクタルデータのインデックスを表します。この場合、配列の最初のフラクタルをチェックしています。

次に、fractals_up[index_fractal]の値がEMPTY_VALUEと等しくないかを確認します。これにより、有効な上向きフラクタルが存在することが確認できます。この条件が満たされた場合、上向きフラクタルの値をlastFractal_value変数に格納します。また、最後に検出されたフラクタルが上向きフラクタルであったことを示すために、lastFractal_directionをFRACTAL_UPに更新します。

同様に、fractals_down[index_fractal]の値がEMPTY_VALUEと等しくないかどうかを確認します。これにより、有効な下向きフラクタルが存在することが確認できます。この条件が満たされた場合、下向きフラクタル値をlastFractal_value変数に保存し、lastFractal_directionをFRACTAL_DOWNに設定して、最後に検出されたフラクタルが下向きであったことを反映します。その後、取得したデータをログに記録し、その有効性を確認できます。

if (lastFractal_value != 0.0 && lastFractal_direction != FRACTAL_NEUTRAL){ //--- Ensure fractal is valid
   Print("FRACTAL VALUE = ",lastFractal_value);
   Print("FRACTAL DIRECTION = ",getLastFractalDirection());
}

これにより、フラクタルデータが記録されます。フラクタルの方向を取得するためにカスタム関数を使用しました。そのコードスニペットは以下のとおりです。

//+------------------------------------------------------------------+
//|     FUNCTION TO GET FRACTAL DIRECTION                            |
//+------------------------------------------------------------------+

string getLastFractalDirection(){
   string direction_fractal = "NEUTRAL"; //--- Default direction set to NEUTRAL
   
   if (lastFractal_direction == FRACTAL_UP) return ("UP"); //--- Return UP if last fractal was up
   else if (lastFractal_direction == FRACTAL_DOWN) return ("DOWN"); //--- Return DOWN if last fractal was down
   
   return (direction_fractal); //--- Return NEUTRAL if no specific direction
}

ここでは、最後に検出されたフラクタルの方向を決定して返す関数「getLastFractalDirection」を定義します。この関数は、最新のフラクタル方向(上向きまたは下向き)を追跡するlastFractal_direction」変数の値をチェックすることによって機能します。まず、文字列変数direction_fractalを初期化し、デフォルトで「NEUTRAL」に設定します。つまり、有効な方向が見つからない場合、またはフラクタル方向が更新されていない場合、関数は結果として「NEUTRAL」を返します。

次に、lastFractal_direction変数の値を確認します。それがFRACTAL_UPに等しい(最後に検出されたフラクタルが上向きフラクタルであったことを示す)場合、関数は文字列「UP」を返します。lastFractal_directionがFRACTAL_DOWNに等しい(最後に検出されたフラクタルが下向きのフラクタルであったことを示す)場合、関数は文字列「DOWN」を返します。これらの条件のどちらも満たされない場合(つまり、上向きまたは下向きのフラクタルが検出されなかったか、方向がまだ中立である)、関数はデフォルトの「NEUTRAL」値を返します。これは、現時点で特定の方向がないことを示します。

以下のように他のインジケーターのデータをログに記録することもできます。

Print("ALLIGATOR JAWS = ",NormalizeDouble(alligator_jaws[1],_Digits));
Print("ALLIGATOR TEETH = ",NormalizeDouble(alligator_teeth[1],_Digits));
Print("ALLIGATOR LIPS = ",NormalizeDouble(alligator_lips[1],_Digits));

Print("AO VALUE = ",NormalizeDouble(ao_values[1],_Digits+1));

if (ac_color[1] == AC_COLOR_UP){
   Print("AC COLOR UP GREEN = ",AC_COLOR_UP);
}
else if (ac_color[1] == AC_COLOR_DOWN){
   Print("AC COLOR DOWN RED = ",AC_COLOR_DOWN);
}

実行すると、次の出力が得られます。

フラクタルの確認

フラクタルの確認

その他のインジケーターの確認

その他のインジケーターの確認

視覚化すると、取得したデータがデータウィンドウに表示される実際のデータと一致していることがわかります。これは成功です。その後、このデータを取引目的で引き続き使用することができます。まず、分析をおこなうために使用するいくつかの必要な関数を次のように定義します。

//+------------------------------------------------------------------+
//|        FUNCTION TO GET CLOSE PRICES                              |
//+------------------------------------------------------------------+

double getClosePrice(int bar_index){
   return (iClose(_Symbol, _Period, bar_index)); //--- Retrieve the close price of the specified bar
}

//+------------------------------------------------------------------+
//|        FUNCTION TO GET ASK PRICES                                |
//+------------------------------------------------------------------+

double getAsk(){
   return (NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits)); //--- Get and normalize the Ask price
}

//+------------------------------------------------------------------+
//|        FUNCTION TO GET BID PRICES                                |
//+------------------------------------------------------------------+

double getBid(){
   return (NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits)); //--- Get and normalize the Bid price
}

ここでは、それぞれ終値、売り値、買い値を取得するための3つの関数を定義します。次に、以下のようにアリゲーターの顎線に基づいて潜在的な取引シグナルをチェックするためのブール変数を定義する必要があります。

bool isBreakdown_jaws_buy = alligator_jaws[1] < getClosePrice(1) //--- Check if breakdown for buy
                            && alligator_jaws[2] > getClosePrice(2);
bool isBreakdown_jaws_sell = alligator_jaws[1] > getClosePrice(1) //--- Check if breakdown for sell
                            && alligator_jaws[2] < getClosePrice(2);

まず、潜在的な買いシグナルのブレークダウン条件を検出するためにisBreakdown_jaws_buyを定義します。条件は、インデックス1(前のバーを表す)のalligator_jaws配列の値が、getClosePrice(1)関数を呼び出して取得される前のバーの終値よりも小さいことです。さらに、インデックス2のalligator_jaws配列の値(その前のバーを表す)は、その前のバーの終値よりも大きくなければなりません。この値は、関数呼び出し「getClosePrice(2)」を使用して取得されます。この組み合わせは、アリゲーターの顎線が前のバーの終値を下回ったが、その前のバーの終値を上回っていたことを示唆しており、これは買い取引の潜在的なセットアップとして解釈できます。

次に、潜在的な売りシグナルのブレークダウン条件を検出するためにisBreakdown_jaws_sellを定義します。この場合、インデックス1のalligator_jaws値は前のバーの終値よりも大きく、インデックス2のalligator_jaws値はその前のバーの終値よりも小さくなります。このシナリオは、アリゲーターの顎線が前のバーの終値を上回ったが、その前のバーの終値を下回っていたことを示し、売り取引の潜在的なセットアップを示唆しています。ここから、ポジションの残りの条件を定義できます。

if (lastFractal_direction == FRACTAL_DOWN //--- Conditions for Buy signal
   && isBreakdown_jaws_buy
   && ac_color[1] == AC_COLOR_UP
   && (ao_values[1] > 0 && ao_values[2] < 0)){
   Print("BUY SIGNAL GENERATED");
   obj_Trade.Buy(0.01,_Symbol,getAsk()); //--- Execute Buy order
}
else if (lastFractal_direction == FRACTAL_UP //--- Conditions for Sell signal
   && isBreakdown_jaws_sell
   && ac_color[1] == AC_COLOR_DOWN
   && (ao_values[1] < 0 && ao_values[2] > 0)){
   Print("SELL SIGNAL GENERATED");
   obj_Trade.Sell(0.01,_Symbol,getBid()); //--- Execute Sell order
}

ここでは、フラクタル方向、アリゲーターの顎線の内訳、Accelerator Oscillator (AC)の色の状態、Awesome Oscillator (AO)の値など、インジケーターの組み合わせに基づいて買いシグナルと売りシグナルを実行するロジックを実装します。

まず、買いシグナルの条件が満たされているかどうかを確認します。lastFractal_directionがFRACTAL_DOWNに設定されていることを確認します。これは、最後に検出されたフラクタルが下向きのフラクタルであったことを意味します。次に、isBreakdown_jaws_buy条件がtrueであるかどうかを確認します。これは、アリゲーターの顎線が価格を下回り、潜在的な買いに向けて設定されていることを示します。

さらに、ac_color[1]がAC_COLOR_UPに等しいことを確認します。これは、Accelerator Oscillator (AC)が上向きの色の状態にあり、強気の市場センチメントを示していることを意味します。最後に、Awesome Oscillator (AO)の値を確認します。ao_values[1]はゼロより大きい値(正の勢いを示す)で、ao_values[2]はゼロより小さい値(以前の負の勢いを示す)である必要があります。この組み合わせは、勢いが逆転し、市場がマイナスからプラスに転じていることを示唆しています。これらの条件がすべて満たされると、買いシグナルが生成され、指定されたロットサイズ(0.01)で売り値で買い注文が実行されます。

一方、売りシグナルの条件が満たされているかどうかを確認します。lastFractal_directionがFRACTAL_UPに設定されていることを確認します。これは、最後に検出されたフラクタルが上向きのフラクタルであったことを意味します。次に、isBreakdown_jaws_sell条件がtrueであるかどうかを確認します。これは、アリゲーターの顎線が価格を上回り、売り注文の可能性がある状態になっていることを示します。

さらに、ac_color[1]がAC_COLOR_DOWNに等しいことを確認します。これは、Accelerator Oscillator (AC)が下向きの色の状態にあり、弱気な市場センチメントを示していることを意味します。最後に、Awesome Oscillator (AO)の値を確認します。ao_values[1]はゼロ未満(負の勢いを示す)で、ao_values[2]はゼロより大きい(以前の正の勢いを示す)必要があります。この組み合わせは、市場がプラスの勢いからマイナスの勢いに反転していることを示唆しています。これらの条件がすべて満たされると、売りシグナルが生成され、指定されたロットサイズ(0.01)の売り注文が買い値で実行されます。

これによりポジションが開きます。ただし、終了注文が出されていないため、ポジションが停止していることがわかります。したがって、AOインジケーターの反転に基づいてポジションをクローズするロジックが必要です。

if (ao_values[1] < 0 && ao_values[2] > 0){ //--- Condition to close all Buy positions
   if (PositionsTotal() > 0){
      Print("CLOSE ALL BUY POSITIONS");
      for (int i=0; i<PositionsTotal(); i++){
         ulong pos_ticket = PositionGetTicket(i); //--- Get position ticket
         if (pos_ticket > 0 && PositionSelectByTicket(pos_ticket)){ //--- Check if ticket is valid
            ENUM_POSITION_TYPE pos_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
            if (pos_type == POSITION_TYPE_BUY){ //--- Close Buy positions
               obj_Trade.PositionClose(pos_ticket);
            }
         }
      }
   }
}
else if (ao_values[1] > 0 && ao_values[2] < 0){ //--- Condition to close all Sell positions
   if (PositionsTotal() > 0){
      Print("CLOSE ALL SELL POSITIONS");
      for (int i=0; i<PositionsTotal(); i++){
         ulong pos_ticket = PositionGetTicket(i); //--- Get position ticket
         if (pos_ticket > 0 && PositionSelectByTicket(pos_ticket)){ //--- Check if ticket is valid
            ENUM_POSITION_TYPE pos_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
            if (pos_type == POSITION_TYPE_SELL){ //--- Close Sell positions
               obj_Trade.PositionClose(pos_ticket);
            }
         }
      }
   }
}

ここでは、Awesome Oscillator (AO)の値に基づいて、すべてのアクティブなポジション(買いまたは売り)をクローズするロジックを実装します。まず、すべての買いポジションをクローズする条件を確認します。ao_values[1]が0未満で、ao_values[2]が0より大きい場合、負の勢いから正の勢いへの潜在的なシフトを示します。これはすべての買いポジションをクローズするための条件です。これをおこなうには、まずPositionsTotal関数を使用して、ポジションが存在するかどうかを確認します。

ポジションがある場合は、各ポジションをループし、PositionGetTicket関数を使用して各ポジションのチケット番号を取得します。各ポジションについて、PositionSelectByTicket関数を使用してチケットを検証し、有効なポジションであることを確認します。次に、PositionGetIntegerを使用して位置タイプを取得し、それをENUM_POSITION_TYPE列挙型にキャストします。ポジションタイプがPOSITION_TYPE_BUYの場合、つまり買いポジションである場合は、obj_Trade.PositionClose(pos_ticket)を使用してポジションをクローズし、確認のために「CLOSE ALL BUY POSITIONS」を出力します。

次に、すべての売りポジションをクローズする条件を確認します。ao_values[1]が0より大きく、ao_values[2]が0より小さい場合、プラスの勢いからマイナスの勢いにシフトする可能性があることを示しており、すべての売りポジションを閉じる必要があることを示しています。同様に、まずポジションが存在するかどうかを確認します。存在する場合は、それらをループし、ポジションチケットを取得し、チケットを検証して、ポジションタイプを確認します。ポジションタイプがPOSITION_TYPE_SELL(売りポジション)である場合は、obj_Trade.PositionClose(pos_ticket)を使用してポジションをクローズし、確認のために「CLOSE ALL SELL POSITIONS」を出力します。

プログラムを実行すると、次の出力が得られます。

買いポジション

うまくいきました。すべてのエントリー条件が満たされたときに、買いポジションを確認してオープンしたことがわかります。戦略の実装については以上です。ここで、ストラテジーテスターでプログラムをテストし、必要に応じて現在の市場状況に適応できるように最適化する必要があります。それは次のセクションでおこなわれます。


戦略のテストと最適化

中核にある実装が完了したら、次のフェーズでは、MetaTrader 5ストラテジーテスターを使用してEAをテストし、さまざまな市場シナリオ内でのパフォーマンスを正確に評価します。このテスト段階では、戦略の動作が期待どおりであることを確認し、結果を最適化するために必要な調整を特定します。ここでは、戦略に不可欠なパラメータに特に焦点を当てた初期最適化をすでに完了しています。

さまざまな取引セッションや条件におけるEAの応答性を評価するために、フラクタルとアリゲーターラインの閾値に特に注意を払いました。この徹底的なテストにより、プログラムが効率的な取引処理で期待される売買シグナルに準拠し、潜在的なエラーを最小限に抑えながら信頼性とパフォーマンスが向上することを検証できました。テストプロセスから得られた結果は次のとおりです。

バックテスト結果

結果

バックテストグラフ

グラフ


結論

この記事では、Profitunity取引戦略を使用してMQL5エキスパートアドバイザー(EA)を作成し、フラクタル、Alligatorインジケーター、Awesome Oscillator (AO)やAccelerator Oscillator (AC)などのオシレーターを統合して戦略的な売買シグナルを識別するプロセスについて説明しました。コア指標と閾値ベースの条件を設定し、市場の勢いと価格のブレイクアウトを活用する取引シグナルを自動化しました。各ステップでは、慎重なコード構築、インジケーターハンドルの設定、戦略基準に基づく売買取引をトリガーするロジックの実装が求められます。実装後、MetaTrader 5のストラテジーテスターを使用してEAを厳密にテストし、さまざまな市場状況での応答性と信頼性を検証し、最適化されたパラメータに基づいた取引実行の精度を重視しました。

免責条項:この記事は、Profitunity取引戦略を使用して、インジケーター駆動型の取引シグナルに基づくカスタムプログラムを構築するための教育ガイドです。紹介された戦略と手法は特定の取引結果を保証するものではなく、慎重に使用することが推奨されます。常に徹底的なテストと検証をおこない、自動取引ソリューションを実際の市場状況や個人のリスク許容度に適応させることが重要です。

この記事では、Profitunity戦略を使用して、MQL5で取引シグナルを自動化するための体系的なアプローチを紹介しました。このガイドが、MQL5開発をさらに深く学ぶきっかけとなり、より洗練された収益性の高い取引システムの作成に繋がることを願っています。コーディングの成功と、取引における成果をお祈りします。

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/16365

プライスアクション分析ツールキットの開発(第2回): Analytical Commentスクリプト プライスアクション分析ツールキットの開発(第2回): Analytical Commentスクリプト
プライスアクションを簡素化するというビジョンに沿って、市場分析を大幅に強化し、十分な情報に基づいた意思決定を支援する新しいツールを導入できることを嬉しく思います。このツールは、前日の価格、重要な支持と抵抗のレベル、取引量などの主要なテクニカル指標を表示し、チャート上に視覚的なヒントを自動的に生成します。
知っておくべきMQL5ウィザードのテクニック(第47回):時間差分を用いた強化学習 知っておくべきMQL5ウィザードのテクニック(第47回):時間差分を用いた強化学習
時間差分学習は、エージェントの訓練中に予測された報酬と実際の報酬の差に基づいてQ値を更新する強化学習のアルゴリズムの一つです。特に、状態と行動のペアにこだわらずにQ値を更新する点に特徴があります。したがって、これまでの記事と同様に、ウィザードで作成したエキスパートアドバイザー(EA)での適用方法を検討していきます。
Connexus Observer(第8回):リクエストObserverの追加 Connexus Observer(第8回):リクエストObserverの追加
連載「Connexusライブラリ」の最終回では、Observerパターンの実装に加え、ファイルパスやメソッド名に関する重要なリファクタリングについて解説します。本連載を通じて、複雑なアプリケーションにおけるHTTP通信を簡素化することを目的としたConnexusの開発全体を取り上げました。
Connexusのクライアント(第7回):クライアント層の追加 Connexusのクライアント(第7回):クライアント層の追加
この記事では、Connexusライブラリの開発を続けます。この章では、リクエストの送信と注文の受信を担当するCHttpClientクラスを構築します。また、モックの概念についても取り上げ、ライブラリをWebRequest関数から切り離すことで、ユーザーの柔軟性を高めます。