
MQL5でパラボリックSARと単純移動平均(SMA)を使用した高速取引戦略アルゴリズムを実装する
はじめに
この記事では、取引アルゴリズムをテストおよび最適化するための重要なプロセスを順を追って解説します。MQL5のストラテジーテスターを使用して、EAを過去のデータに対してバックテストします。言い換えると、私たちのアルゴリズムが過去において実際の市場環境下でどれほどのパフォーマンスを発揮したかを確認するということです。EAのパフォーマンスを評価する中で、利益率、ドローダウン、勝率など、さまざまなパフォーマンス指標の読み方についても説明します。それらの指標が、アルゴリズムの信頼性や収益性について何を示しているかを理解することが目的です。この記事を読み終えるころには、高速取引戦略の実装方法と、その戦略を成功させるために必要な要素について、より明確な理解を得られるでしょう。本記事では、以下のトピックを取り上げます。
高速取引戦略は、短時間で複数の取引を実行し、ポジションを多くの場合1時間未満でクローズすることによって、迅速かつ頻繁な市場の動きから利益を得ることを目的としています。このアプローチは、長期的なトレンドに着目する従来の戦略とは異なり、変動の激しい銘柄における小さな価格変動を捉えることを重視しています。この戦略の成功には、市場データをほぼ瞬時に処理し反応する能力が求められます。そのため、EAのような自動化システムは、取引を効率的に実行する上で不可欠な存在となります。
この戦略の効果を高める鍵となるのが、パラボリックSARと単純移動平均(SMA)といったテクニカルインジケーターの活用です。これらのインジケーターはトレンドの反転を見極めたり、価格データを平滑化したりする役割を担っています。高頻度取引アルゴリズムに組み込むことで、戦略は市場の変化に素早く適応し、シグナルの精度と取引の実行精度を維持することが可能になります。適切に実装されれば、高速取引戦略は短期間での利益を生む可能性がありますが、その一方でコストとリスクの慎重な管理が求められます。
インジケーターの理解:パラボリックSARとSMA
効果的な高速取引戦略を構築するには、取引判断を導く重要なテクニカルインジケーターを理解することが不可欠です。その中でも特に有用なのが、パラボリックSAR(ストップ・アンド・リバース)と単純移動平均(SMA)です。SMAは、最も古く、かつ最も頻繁に使用されているトレンドフォロー型インジケーターの一つです。一方、パラボリックSARはそれに比べて比較的新しいツールですが、決してマイナーな存在ではなく、どちらのインジケーターも市場の状況を判断し、取引機会を見極める上で非常に有効です。
パラボリックSARは、トレンドの継続や転換点を把握するために設計されたインジケーターで、価格の方向転換の可能性を特定することを目的としています。このインジケーターは、価格に対してドットを上または下に連続してプロットすることで機能します。これらのドットの位置は、「SAR(ストップ・アンド・リバース)」の値を基にしています。パラボリックSARを取引戦略に組み込むことで、ドットの位置を基準に、買い・売り・空売りなどのポジション判断をおこなうことが可能になります。価格がSARドットの上にあれば上昇(強気)トレンド、下にあれば下降(弱気)トレンドと判断されます。インジケーターはデフォルト設定で使用します。これは、以下の図に示す通りです。
以下は、パラボリックSARインジケーターの設定です。
私たちの取引戦略におけるもう一つの重要な要素が、単純移動平均(SMA)です。SMAは、指定された期間の価格データを取得し、それを「平滑化」することで、全体的なトレンドを視覚的にわかりやすく示します。このインジケーターを使えば、トレンドの方向をよりシンプルに判断することが可能です。たとえば、SMAが上向きに傾いていれば、市場は上昇トレンドにあると見なすことができ、逆にSMAが下向きに傾いていれば、下降トレンドにあると判断できます。SMAは「トレンドフィルター」として機能し、現在の相場がロング(上昇トレンド)、ショート(下降トレンド)、あるいは取引を控えるべき(価格がSMAの横ばい線付近にある)状況かを判断する手助けをします。ここでは、期間60の単純移動平均を使用します。これは、以下の図に示す通りです。
以下は、単純移動平均インジケーターの設定です。
パラボリックSARと単純移動平均を組み合わせて使用することで、市場の状況をより包括的に把握することができます。SARは、現在のトレンドに何が起きているかを即座に示すシグナルとして読み取ることができ、しばしばトレンドの反転を事前に示唆します。一方、SMAはより長期間のデータを基にしており、その分トレンドの方向性をより確実に確認することができます。これらを組み合わせると、以下のようになります。
提供された戦略の概要を使用して、MQL5で戦略のEAを作成しましょう。
MQL5での実装
高速取引戦略の理論を理解したところで、次はこの理論を自動化し、MetaTrader 5 (MT5)用のMetaQuotes Language 5 (MQL5)を使って、EAを作成していきましょう。
EAを作成するには、MetaTrader 5端末で[ツール]タブをクリックし、[MetaQuotes言語エディタ]を選択するか、キーボードのF4を押します。または、ツールバーのIDE(統合開発環境)アイコンをクリックすることもできます。これにより、自動売買ロボット、テクニカルインジケーター、スクリプト、関数のライブラリを作成できるMetaQuotes言語エディタ環境が開きます。
MetaEditorを開いたら、ツールバーの[ファイル]タブで[新しいファイル]を選択するか、CTRL+Nキーを押して新規ドキュメントを開きます。または、[ツール]タブの新規アイコンをクリックすることもできます。MQLウィザードのポップアップが表示されます。
ウィザードが表示されたら、[EA(テンプレート)]を選択し、[次へ]をクリックします。
EAの一般プロパティで、[名前]フィールドにEAのファイル名を入力します。フォルダが存在しない場合にフォルダを指定または作成するには、EA名の前にバックスラッシュを使用することに注意してください。例えば、ここではデフォルトで「Experts\」となっています。つまり、私たちのEAはExpertsフォルダに作成され、そこで見つけることができます。他のフィールドはごく簡単ですが、ウィザードの一番下にあるリンクから、正確な手順を知ることができます。
希望するEAファイル名を入力した後、[次へ]をクリックし、[完了]をクリックします。ここまでくれば、あとはコードを書いて戦略をプログラムするだけです。
まず、EAに関するメタデータを定義することから始めます。これには、EA名、著作権情報、MetaQuotes Webサイトへのリンクが含まれます。EAのバージョンも指定し、1.00とします。
//+------------------------------------------------------------------+ //| #1. RAPID FIRE.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." // Set the copyright property for the Expert Advisor #property link "https://www.mql5.com" // Set the link property for the Expert Advisor #property version "1.00" // Set the version of the Expert Advisor
プログラムをロードすると、下図のような情報が表示されます。
まず、ソースコードの先頭で#includeを使用して取引インスタンスをインクルードします。これでCTradeクラスにアクセスできるようになります。これを使用して取引オブジェクトを作成します。これは取引を開始するために必要なので、非常に重要です。
#include <Trade/Trade.mqh> // Include the MQL5 standard library for trading operations CTrade obj_Trade; // Create an instance of the CTrade class to handle trade operations
プリプロセッサは「#include<Trade/Trade.mqh>」という行をTrade.mqhというファイルの内容に置き換えます。角括弧は、Trade.mqhファイルが標準ディレクトリ(通常、terminal_installation_directory\MQL5\Include)から取得されることを示します。カレントディレクトリは検索に含まれません。この行はプログラム中のどこにでも配置できますが、通常は、より良いコード構造と参照を容易にするために、すべてのインクルージョンはソースコードの先頭に置かれます。CTradeクラスのobj_Tradeオブジェクトを宣言すると、MQL5開発者のおかげで、そのクラスに含まれるメソッドに簡単にアクセスできるようになります。
戦略に必要なインジケーターを含めるために、インジケーターハンドルを作成する必要があります。
int handleSMA = INVALID_HANDLE, handleSAR = INVALID_HANDLE; // Initialize handles for SMA and SAR indicators
ここでは、まず2つの整数型の変数「handleSMA」と「handleSAR」を宣言し、初期化します。これらは、EA内で使用する予定の2つのテクニカルインジケーターのハンドルとして機能します。MQL5では、特定の関数を使ってインジケーターを作成すると、そのインジケーターに一意のハンドルが割り当てられます。このハンドルを使うことで、プログラム内の任意の場所からインジケーターにアクセスできるようになります。両方の変数には、初期値として定数「INVALID_HANDLE」を代入しています。これにより、コンパイル後にプログラムのフローをチェックし忘れた場合でも、無効なハンドルを参照するリスクを避けることができます。これらのインジケーターは、ハンドルを正しく管理し、無効な値を参照しないように注意すれば、問題なく動作します。
次に、インジケーターから取得した値やデータを格納するための配列を用意します。
double sma_data[], sar_data[]; // Arrays to store SMA and SAR indicator data
ここでは、SMA(単純移動平均)インジケーターとSAR(パラボリックSAR)インジケーターによって生成されたデータポイントを格納するために、2つの動的配列「sma_data」と「sar_data」を定義します。これらの配列には、それぞれのインジケーターで計算された最新の値が格納され、取引シグナルの生成時に自由に参照・分析できるようになります。シグナルは、シグナルラインのクロスオーバーによって生成される場合があります。また、現在のトレンドに沿った取引や、トレンドの反転に基づく取引シグナルを生成するために、これらの配列に保持されている過去の値を活用することができます。過去のデータを利用することで、インジケーターのシグナルや、取引対象の資産における価格の動きをより正確に解釈できるようになります。
次に必要なのは、OnInitイベントハンドラです。このハンドラは、チャート上でEAが初期化されるときに自動的に呼び出されるため、必要不可欠です。この関数は、必要なインジケーターハンドルの作成、変数の初期化、リソースの準備など、EAのセットアップをおこないます。言い換えれば、OnInitはEAが市場データの処理を開始する前に、すべての構成が正しくおこなわれていることを保証する組み込み関数です。以下がコードです。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ // OnInit is called when the EA is initialized on the chart //... }
OnInitイベントハンドラでは、データ値が割り当てられるようにインジケーターハンドルを初期化する必要があります。
handleSMA = iMA(_Symbol,PERIOD_M1,60,0,MODE_SMA,PRICE_CLOSE); // Create an SMA (Simple Moving Average) indicator handle for the M1 timeframe
ここでは、iMA関数を使用して、単純移動平均(SMA)インジケーターのハンドルを作成します。このハンドルを使用することで、指定した取引銘柄と時間足に対するSMAの値にアクセスできるようになります。今回は、現在の取引銘柄(_Symbol)に対して、1分足(PERIOD_M1)のチャート上で、60本分のバーを対象にSMAを設定します。パラメータの「0」は、移動平均の計算においてシフトをおこなわないことを意味します。また、MODE_SMA定数を指定することで、計算モードとして単純移動平均を選択しています。最後に、PRICE_CLOSEを指定することで、各バーの終値をもとにインジケーターを計算します。結果のハンドルを変数「handleSMA」に保存します。続いて、パラボリックSARインジケーターのハンドルを作成します。
handleSAR = iSAR(_Symbol,PERIOD_M1,0.02,0.2); // Create a SAR (Parabolic SAR) indicator handle for the M1 timeframe
同様に、iSAR関数を使用して、パラボリックSAR(SAR)インジケーターのハンドルを作成します。iSAR関数は、指定した取引銘柄と時間足におけるパラボリックSARの値を返します。ここでは、現在の取引銘柄(_Symbol)および1分足(PERIOD_M1)に対して使用しています。パラメータ0.02と0.2は、それぞれSARのステップと最大値を表しており、インジケーターが価格変動にどれだけ敏感に反応するかを制御します。このハンドルを使用することで、市場のトレンドや価格反転に基づいて構築された最初の取引戦略に不可欠なSARデータへアクセス可能になります。
なお、インジケーターハンドルはデフォルトで10から始まり、1ずつ増加していきます。したがって、2つのインジケーターを使用している場合、ハンドル値としては10と11になるはずです。これらの値を可視化するために、ログに出力して確認してみましょう。
Print("SMA Handle = ",handleSMA); Print("SAR Handle = ",handleSAR);
取得される値は次のとおりです。
これで値が正しく記録されるようになりました。次に、インジケーターハンドルが空でないことを確認しましょう。
// Check if the handles for either the SMA or SAR are invalid (indicating failure) if (handleSMA == INVALID_HANDLE || handleSAR == INVALID_HANDLE){ Print("ERROR: FAILED TO CREATE SMA/SAR HANDLE. REVERTING NOW"); // Print error message in case of failure return (INIT_FAILED); // Return failure code, stopping the EA from running }
このセクションでは、SMAおよびSARインジケーターハンドルの作成中に発生する重大なエラーを検出するためのメカニズムを構築します。これらのハンドルが正常に作成されなかった場合、EAは正しく機能できません。そのため、handleSMAまたはhandleSARがINVALID_HANDLEのままかどうかを確認します。これは、どちらか一方、または両方のインジケーターの初期化に失敗したことを意味します。いずれかのハンドルが無効である場合、エラーメッセージ「ERROR:FAILED TO CREATE SMA/SAR HANDLE.REVERTING NOW.」を出力し、初期化関数からINIT_FAILEDを返します。Iこれにより、EAが不完全な状態で動作を続けて誤った取引判断を下すのを防ぐ、堅牢なエラー処理ルーチンを実現しています。その後、インジケーターのデータを格納する配列を時系列として設定する必要があります。これを実行するコードスニペットは以下の通りです。
// Configure the SMA and SAR data arrays to work as series, with the newest data at index 0 ArraySetAsSeries(sma_data,true); ArraySetAsSeries(sar_data,true);
ストレージ配列を時系列データとして設定し、最新の情報をインデックス0に配置します。これを実現するために、ArraySetAsSeries関数を使用し、最初の引数として「sma_data」と「sar_data」の2つの配列を指定します。さらに、配列が系列として扱われるように、2番目の引数にtrueを指定します。これは、インジケーターが表すデータが取引意思決定ルーチンに渡される際に、取引ロジックの通常の決定タイミングで最新のインジケーター値にアクセスできるようにするために必要なステップです。ロジックの次の部分では、2つのインジケーターの現在と過去の値を参照します。最後に、この時点に到達した場合、すべてが正しく初期化されていることを意味し、成功した初期化インスタンスを返します。
return(INIT_SUCCEEDED); // Return success code to indicate successful initialization
ここまでは、初期化セクションのすべてが正しく機能していました。プログラムの初期化を担当するソースコードの全文は以下の通りです。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ // OnInit is called when the EA is initialized on the chart handleSMA = iMA(_Symbol,PERIOD_M1,60,0,MODE_SMA,PRICE_CLOSE); // Create an SMA (Simple Moving Average) indicator handle for the M1 timeframe handleSAR = iSAR(_Symbol,PERIOD_M1,0.02,0.2); // Create a SAR (Parabolic SAR) indicator handle for the M1 timeframe Print("SMA Handle = ",handleSMA); Print("SAR Handle = ",handleSAR); // Check if the handles for either the SMA or SAR are invalid (indicating failure) if (handleSMA == INVALID_HANDLE || handleSAR == INVALID_HANDLE){ Print("ERROR: FAILED TO CREATE SMA/SAR HANDLE. REVERTING NOW"); // Print error message in case of failure return (INIT_FAILED); // Return failure code, stopping the EA from running } // Configure the SMA and SAR data arrays to work as series, with the newest data at index 0 ArraySetAsSeries(sma_data,true); ArraySetAsSeries(sar_data,true); return(INIT_SUCCEEDED); // Return success code to indicate successful initialization }
次に、プログラムが初期化解除されるときに呼び出される関数であるOnDeinitイベントハンドラに進みます。
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason){ // OnDeinit is called when the EA is removed from the chart or terminated //... }
OnDeinit関数は、EAがチャートから削除されたとき、またはターミナルがシャットダウンしたときに呼び出されます。このイベントハンドラを使用して、正しい維持管理とリソース管理をおこなわなければなりません。EAが終了したら、初期化フェーズで作成したインジケーターのハンドルをすべて解放しなければなりません。これをおこなわないと、使用したメモリの場所が残ってしまう可能性があり、非効率的になります。不要なリソースを残すリスクは絶対に避けたいと考えました。これが、OnDeinitが重要である理由であり、あらゆるプログラミング環境でクリーンアップ手順が不可欠である理由です。
// Release the indicator handles to free up resources IndicatorRelease(handleSMA); IndicatorRelease(handleSAR);
使用するために確保したすべてのリソースをクリーンアップします。このクリーンアップを実行するために、IndicatorRelease関数を使用します。この関数は、最初に使用を開始した際に保存したのと同様に、割り当てて初期化した各ハンドルごとに個別に呼び出します。これにより、リソースが割り当てられた順番の逆順で解放されることになります。ここでは、特にSMAおよびSARインジケーターについて取り上げます。特に複数のEAを使用している場合や、長時間プラットフォームを稼動させている場合は、プラットフォームのパフォーマンスを維持するためにクリーンアップは非常に重要です。従って、リソース解放のための完全なソースコードは以下の通りです。
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason){ // OnDeinit is called when the EA is removed from the chart or terminated // Release the indicator handles to free up resources IndicatorRelease(handleSMA); IndicatorRelease(handleSAR); }
次に、価格が更新されるたびに取引機会をチェックする必要があります。これは、OnTickイベントハンドラで実現されます。
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ // OnTick is called whenever there is a new market tick (price update) //... }
イベントハンドラ関数OnTickは、新しいティックまたは市場状況の変化が発生するたびに、最新の価格情報を実行して処理します。これは、EAの動作に不可欠な部分です。これは、取引ロジックを実行する場所であり、取引条件は、利益を生む取引を生み出すように構成されているためです。市場データが変化したとき、市場の現状を判断し、ポジションを建てるか決済するかを決定します。この関数は、市場環境の変化に応じて頻繁に実行されるため、戦略がリアルタイムで作動し、現在の価格や市場インジケーターの値の変化に対応できます。
現在の市況を常に更新するためには、現在の価格相場の値を入手する必要があります。
double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits); // Get and normalize the Ask price double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits); // Get and normalize the Bid price
ここでは、取引されている銘柄の最新の売呼値と買呼値を取得します。これらの価格を取得するために、SymbolInfoDouble関数を使用します。売値にはSYMBOL_ASKを指定し、買値にはSYMBOL_BIDを指定します。価格を取得した後、NormalizeDouble関数を使用して、価格を_Digitsで定義された小数点以下の桁数に丸めます。このステップは、標準化された正確な価格を使用して取引業務を確実に実行するために非常に重要です。もし四捨五入しなければ、浮動小数点の不正確さが運行価格の計算に誤解を招く結果をもたらす可能性があります。次に、そのインジケーター値をコピーして分析や取引操作に使用します。
// Retrieve the last 3 values of the SMA indicator into the sma_data array if (CopyBuffer(handleSMA,0,0,3,sma_data) < 3){ Print("ERROR: NOT ENOUGH DATA FROM SMA FOR FURTHER ANALYSIS. REVERTING"); // Print error if insufficient SMA data return; // Exit the function if not enough data is available }
CopyBuffer関数を使用して、単純移動平均インジケーターの最新の3つの値を取得します。CopyBuffer関数は、SMAインジケーターハンドル、SMAデータバッファインデックス、開始位置(この場合は最新の値)、取得する値の数(3)、およびデータを格納する配列(sma_data)を引数として受け取ります。SMA値を配列にコピーした後、正しくコピーされているかどうかを確認します。この時点でエラーが発生した場合、ログにエラーメッセージを出力し、関数を終了して、欠陥のあるまたは不完全なデータに基づいて取引ロジックを実行しないようにします。
同様に、CopyBuffer関数を使用してSARインジケーターデータを取得します。次のコードスニペットが使用されます。
// Retrieve the last 3 values of the SAR indicator into the sar_data array if (CopyBuffer(handleSAR,0,0,3,sar_data) < 3){ Print("ERROR: NOT ENOUGH DATA FROM SAR FOR FURTHER ANALYSIS. REVERTING"); // Print error if insufficient SAR data return; // Exit the function if not enough data is available }
現時点で知っておく必要があるのは、データを保存するバーの開始インデックスとバッファインデックスだけです。以下のように可視化してみましょう。
データが正しく取得されたかどうかを確認するために、データを操作ログに出力してみましょう。
ArrayPrint(sma_data,_Digits," , "); ArrayPrint(sar_data,_Digits," , ");
ArrayPrint関数を使用して、「sma_data」配列と「sar_data」配列の内容を表示します。ArrayPrintは、配列の内容を端末に出力する基本的な関数で、作業中のデータをシンプルに視覚化するのに役立ちます。この関数を使用するには、次の3つの情報を渡す必要があります。
- 出力する配列(sma_dataまたはsar_data)
- 表示される値の精度(_Digits)、これにより表示される小数点以下の桁数が決まります。
- 出力内で印刷された値の間に使用する区切り文字(,)
SMA配列とSAR配列の内容を印刷することで、アルゴリズムが使用している実際の数値を追跡でき、デバッグに役立ちます。また、バックテスト中にこのデータをチェックすることで、必要なデータが正しく取得されているかどうかも確認できます。
画像から、データが正しく取得され、保存されていることが確認できます。赤色のデータは移動平均を、青色のデータはパラボリックSARを表しています。クロスヘアから、2本目のバー(インデックス1)を参照していることがわかります。要求どおりに3つのデータ値が取得されていることが明らかとなりました。それでは、次に必要なバーの値を取得する処理へと進みます。
// Get the low prices for the current and previous bars on the M1 timeframe double low0 = iLow(_Symbol,PERIOD_M1,0); // Low of the current bar double low1 = iLow(_Symbol,PERIOD_M1,1); // Low of the previous bar
ここでは、iLow関数を使用して、1分足の時間枠における現在のバーおよび前のバーから安値を抽出します。最初のパラメータ_Symbolは、EAが動作している取引銘柄(たとえばEUR/USD)に自動的に適用されます。2番目のパラメータPERIOD_M1は、1分足チャートであることを示しており、急速な価格変動に基づく短期取引を前提とする高速戦略においては非常に重要です。iLow(_Symbol, PERIOD_M1, 0)における3番目のパラメータ「0」は、現在形成中のバーの安値を取得することを意味します。同様に、iLow(_Symbol, PERIOD_M1, 1)では、パラメータ「1」により、直前に確定したバーの安値を取得します。これらの取得値は、それぞれdouble型の変数「low0」および「low1」に格納されます。
同様のロジックを用いて、現在のバーと直前のバーの高値を取得する場合はiHigh関数を使用します。
// Get the high prices for the current and previous bars on the M1 timeframe double high0 = iHigh(_Symbol,PERIOD_M1,0); // High of the current bar double high1 = iHigh(_Symbol,PERIOD_M1,1); // High of the previous bar
ここで唯一変わるのは、指定されたバーインデックスと時間枠の高値データを取得する関数iHighです。取得したデータが正しいことを確認するために、Print関数を使用して再度出力してみましょう。
Print("High bar 0 = ",high0,", High bar 1 = ",high1); Print("Low bar 0 = ",low0,", Low bar 1 = ",low1);
以下の通りデータを確認できます。
うまくいきました。次に、取引ロジックの作成に進みます。ただし、すべてのティックで取引ロジックを実行する必要はありません。したがって、バーごとに1回だけ取引がおこなわれるようにするメカニズムを作成しましょう。
// Define a static variable to track the last time a signal was generated static datetime signalTime = 0; datetime currTime0 = iTime(_Symbol,PERIOD_M1,0); // Get the time of the current bar
このセクションでは、最後の取引シグナルが生成された時刻を追跡するための変数「signalTime」を作成します。この変数を静的にすることで、OnTick関数の呼び出し間でその値が維持されるようになります。「signalTime」に静的ストレージ期間がない場合、OnTickが呼び出されるたびに割り当てられ、OnTickの実行が終了するとその値は消えてしまいます。シグナル時間は各バーに対して1回だけ設定し、次のバーが開始されるまでその値を維持します。したがって、最初のシグナルが生成された後にのみ値を持つように、最初は0に設定します。同じバーで2番目(または複数)のシグナルが生成されないようにするには、現在のバーの時間を変数に格納されている値と比較します。その後、取引ロジックを定義できるようになります。
// Check for BUY signal conditions: // - Current SAR is below the current low (bullish) // - Previous SAR was above the previous high (bullish reversal) // - SMA is below the current Ask price (indicating upward momentum) // - No other positions are currently open (PositionsTotal() == 0) // - The signal hasn't already been generated on the current bar if (sar_data[0] < low0 && sar_data[1] > high1 && signalTime != currTime0 && sma_data[0] < Ask && PositionsTotal() == 0){ Print("BUY SIGNAL @ ",TimeCurrent()); // Print buy signal with timestamp signalTime = currTime0; // Update the signal time to the current bar time }
ここでは、パラボリックSARおよびSMAインジケーターの同時動作とその他のいくつかの制約に基づいて、買いシグナルを発行するための条件を検証します。パラボリックSARからの強気シグナルを得るには、現在のSAR値(sar_data[0])が現在の安値(low0)を下回っている必要があります。同時に、前回のSAR値(sar_data[1])は前回の高値(high1)を上回っていた必要があります。強気のSMAシグナルの資格を得るには、SMAが現在のAsk価格を下回っている必要があります(sma_data[0] < Ask)。
さらに、他のポジションがないことを確認します(PositionsTotal==0)。同時に複数の取引を開くことは望ましくありません。次に、「signalTime」と「currTime0」を比較して、現在のバーに対してシグナルが生成されていないことを確認します。これらすべてのチェックに合格すると、購入シグナルの生成を通知するメッセージを出力します。また、シグナル時間変数を現在の時刻に更新します。この巧妙なトリックにより、シグナル生成をバーごとに1回だけに制限できるようになります。結局のところ、私たちがやっていることは、EAが特定の市場状況にのみ反応し、不必要な作業をおこなわないようにすることです。得られた結果は次のとおりです。
シグナルを受け取ったので、買いポジションを開きます。
obj_Trade.Buy(0.01,_Symbol,Ask,Ask-150*_Point,Ask+100*_Point); // Execute a buy order with a lot size of 0.01, stop loss and take profit
ここでは、CTradeクラスのBuyメソッド(作成したobj_Tradeオブジェクトによって表されます)を使用して、買い注文を実行します。パラメータの内訳は次のとおりです。
- 0.01:取引のロットサイズ。ここでは、0.01ロットの小さなポジションサイズを指定しています。
- _Symbol:EAが関連付けられている取引銘柄(通貨ペア、株式など)。銘柄は、組み込みの_Symbol変数を使用して自動的に検出されます。
- Ask:買い注文が実行される価格であり、市場の現在の売り価格です。買い取引では、通常、Ask価格が使用されます。
- Ask - 150 * _Point:ストップロスレベル。市場が取引に不利な方向に動いた場合に潜在的な損失を制限するために、ストップロスを売り値より150ポイント下に設定しました。
- Ask + 100 * _Point:テイクプロフィットレベル。テイクプロフィットをAsk価格より100ポイント上に設定しました。つまり、市場がこの利益レベルに達すると、取引は自動的に終了します。
この注文を出すことで、リスクと報酬を管理するために、事前に定義されたストップロスとテイクプロフィットレベルで、現在の売り価格で買い取引を開始するようにEAに指示します。買いシグナルを確認し、買い注文を開くための最終的なコードスニペットは次のとおりです。
// Check for BUY signal conditions: // - Current SAR is below the current low (bullish) // - Previous SAR was above the previous high (bullish reversal) // - SMA is below the current Ask price (indicating upward momentum) // - No other positions are currently open (PositionsTotal() == 0) // - The signal hasn't already been generated on the current bar if (sar_data[0] < low0 && sar_data[1] > high1 && signalTime != currTime0 && sma_data[0] < Ask && PositionsTotal() == 0){ Print("BUY SIGNAL @ ",TimeCurrent()); // Print buy signal with timestamp signalTime = currTime0; // Update the signal time to the current bar time obj_Trade.Buy(0.01,_Symbol,Ask,Ask-150*_Point,Ask+100*_Point); // Execute a buy order with a lot size of 0.01, stop loss and take profit }
売りシグナルを確認して売り注文を開くには、同様のロジックが適用されます。
// Check for SELL signal conditions: // - Current SAR is above the current high (bearish) // - Previous SAR was below the previous low (bearish reversal) // - SMA is above the current Bid price (indicating downward momentum) // - No other positions are currently open (PositionsTotal() == 0) // - The signal hasn't already been generated on the current bar else if (sar_data[0] > high0 && sar_data[1] < low1 && signalTime != currTime0 && sma_data[0] > Bid && PositionsTotal() == 0){ Print("SELL SIGNAL @ ",TimeCurrent()); // Print sell signal with timestamp signalTime = currTime0; // Update the signal time to the current bar time obj_Trade.Sell(0.01,_Symbol,Bid,Bid+150*_Point,Bid-100*_Point); // Execute a sell order with a lot size of 0.01, stop loss and take profit }
ここでは、特定の市場条件が揃ったときに実行される売り取引ロジックを実装します。まず、パラボリックSAR (SAR)インジケーターが弱気トレンドを示しているかを確認します。これは、最新のSARデータとローソク足の価格を比較することで判断します。現在の足においてSARが高値を上回っており(sar_data[0] > high0)、前の足ではSARが安値を下回っていた(sar_data[1] < low1)場合、これは弱気への反転の兆候と考えられます。SARによるトレンドのシグナルは、「取引可能」と判断できるモメンタムである可能性があります。次に単純移動平均線(SMA)を確認します。SMAが現在のBid価格よりも上にある(sma_data[0] > Bid)ことが必要で、これは下降トレンドが継続する可能性、すなわち「取引可能」な状態を示しています。
これらの条件がすべて満たされた場合、売りシグナルを発行し、ログに記録します("Print("SELL SIGNAL @ ", TimeCurrent())")。signalTime変数には現在のバーの時間を記録し、1本のバー内で複数の売りシグナルが出ないように制御します。取引の実行にはオブジェクト関数「obj_Trade.Sell」関数を使用します。弱気反転の兆候が見られるタイミングで、システマティックに市場へのエントリーをおこないます。リスクを適切に管理するため、ストップロス注文とテイクプロフィット注文も併せて設定します。売り確認の設定は次のとおりです。
ここまでのところ、高速取引EAアルゴリズムを正しく作成したことは明らかです。したがって、取引の確認とポジションのオープンを担当するOnTickの完全なソースコードは次のとおりです。
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ // OnTick is called whenever there is a new market tick (price update) double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits); // Get and normalize the Ask price double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits); // Get and normalize the Bid price // Retrieve the last 3 values of the SMA indicator into the sma_data array if (CopyBuffer(handleSMA,0,0,3,sma_data) < 3){ Print("ERROR: NOT ENOUGH DATA FROM SMA FOR FURTHER ANALYSIS. REVERTING"); // Print error if insufficient SMA data return; // Exit the function if not enough data is available } // Retrieve the last 3 values of the SAR indicator into the sar_data array if (CopyBuffer(handleSAR,0,0,3,sar_data) < 3){ Print("ERROR: NOT ENOUGH DATA FROM SAR FOR FURTHER ANALYSIS. REVERTING"); // Print error if insufficient SAR data return; // Exit the function if not enough data is available } //ArrayPrint(sma_data,_Digits," , "); //ArrayPrint(sar_data,_Digits," , "); // Get the low prices for the current and previous bars on the M1 timeframe double low0 = iLow(_Symbol,PERIOD_M1,0); // Low of the current bar double low1 = iLow(_Symbol,PERIOD_M1,1); // Low of the previous bar // Get the high prices for the current and previous bars on the M1 timeframe double high0 = iHigh(_Symbol,PERIOD_M1,0); // High of the current bar double high1 = iHigh(_Symbol,PERIOD_M1,1); // High of the previous bar //Print("High bar 0 = ",high0,", High bar 1 = ",high1); //Print("Low bar 0 = ",low0,", Low bar 1 = ",low1); // Define a static variable to track the last time a signal was generated static datetime signalTime = 0; datetime currTime0 = iTime(_Symbol,PERIOD_M1,0); // Get the time of the current bar // Check for BUY signal conditions: // - Current SAR is below the current low (bullish) // - Previous SAR was above the previous high (bullish reversal) // - SMA is below the current Ask price (indicating upward momentum) // - No other positions are currently open (PositionsTotal() == 0) // - The signal hasn't already been generated on the current bar if (sar_data[0] < low0 && sar_data[1] > high1 && signalTime != currTime0 && sma_data[0] < Ask && PositionsTotal() == 0){ Print("BUY SIGNAL @ ",TimeCurrent()); // Print buy signal with timestamp signalTime = currTime0; // Update the signal time to the current bar time obj_Trade.Buy(0.01,_Symbol,Ask,Ask-150*_Point,Ask+100*_Point); // Execute a buy order with a lot size of 0.01, stop loss and take profit } // Check for SELL signal conditions: // - Current SAR is above the current high (bearish) // - Previous SAR was below the previous low (bearish reversal) // - SMA is above the current Bid price (indicating downward momentum) // - No other positions are currently open (PositionsTotal() == 0) // - The signal hasn't already been generated on the current bar else if (sar_data[0] > high0 && sar_data[1] < low1 && signalTime != currTime0 && sma_data[0] > Bid && PositionsTotal() == 0){ Print("SELL SIGNAL @ ",TimeCurrent()); // Print sell signal with timestamp signalTime = currTime0; // Update the signal time to the current bar time obj_Trade.Sell(0.01,_Symbol,Bid,Bid+150*_Point,Bid-100*_Point); // Execute a sell order with a lot size of 0.01, stop loss and take profit } } //+------------------------------------------------------------------+
プログラムは作成しました。次に、EAのテストをおこない、利益を最大化するために最適化する必要があります。これは次のセクションで説明します。
テストと最適化
このセクションでは、MetaTrader 5のストラテジーテスターを用いた、高速取引戦略のテストおよび最適化に焦点を当てています。テストは不可欠なプロセスであり、EAが想定どおりに機能しているか、また様々な市場環境下でも安定したパフォーマンスを発揮できるかを検証するためにおこないます。EAのテストを開始するには、まずEAをストラテジーテスターに読み込み、使用したい通貨ペア(銘柄)と時間足を選択します(本戦略ではM1時間足を使用)。さらに、バックテストを実施する期間も設定します。バックテストにより、指定した戦略とパラメータに基づいて、EAが過去の相場でどのように機能したかをシミュレーションすることができます。これにより、実際の運用環境でEAが誤作動を起こす可能性のある問題点を事前に洗い出すことが可能となります。ストラテジーテスターを開くには、[表示]をクリックし、[ストラテジーテスター]を選択します。
開いたら、[概要]タブに移動して可視化を選択し、設定タブに切り替えてプログラムをロードし、必要な設定をおこないます。ここでの場合、少量のデータで作業するため、テスト期間は今月のみとなります。
テストの結果、次の結果が得られました。
テスト段階の結果を綿密に分析することが重要です。特に、総純利益、最大ドローダウン、勝率といった主要なパフォーマンス指標に注目します。これらの数値は、戦略の有効性だけでなく、その弱点や全体的な堅牢性についての洞察を与えてくれます。また、ストラテジーテスターが出力するトレードレポートの確認も不可欠です。これにより、EAがどのような取引をおこなっているのか(またはおこなっていないのか)を把握し、さまざまな市場環境でのEAの「判断基準」や挙動を理解する助けになります。結果に満足できない場合は、SMAやSARインジケーターの設定パラメータを見直すか、戦略ロジックそのものを深く分析し、なぜ期待通りの成果が出ないのかを明らかにする必要があります。
最適な取引戦略を見つけるには、市場に合わせて調整(チューニング)することが欠かせません。そのために使用するのが「戦略最適化」と呼ばれる手法です。戦略最適化は一度やって終わりというものではなく、システムがさまざまな設定でどのように機能するかを観察し、複数のテスト全体で一貫したパフォーマンスを示す構成を選定する継続的なプロセスです。このようなテストにより、戦略の鍵となる最適パラメータを特定し、それらを活用して戦略の性能を最大限に引き出すことができます。これらの「鍵」が見つかった後は、EAを再実行し、ウォークフォワード期間での検証をおこなわなければなりません。さもなければ、私たちは単に市場の未来を当てずっぽうで予測しているだけの状態に等しいからです。最適化を実行するには、反復処理をおこなうための入力パラメーターを設定する必要があります。以下に、その実装ロジックを示します。
input int sl_points = 150; // Stoploss points input int tp_points = 100; // Takeprofit points
最適化すると、次の結果が得られます。
最適化された結果のグラフは次のようになります。
最終的に、テストレポートは次のようになります。
結論
本記事では、MQL5で開発された高速取引EAについて解説しました。このEAは、短時間で素早くエントリー・エグジットをおこなう戦略に基づいており、トレンドの反転を示すパラボリックSARと、市場の勢いを測定する単純移動平均(SMA)という2つの主要テクニカル指標を中核としています。これらのインジケーターは、EAの取引ロジックの中核を形成します。
インジケーターの設定方法、データハンドルの構築、取引管理の実装といった具体的な内容を通して、EAが市場とどのように連携して動作するのかを詳しく解説しました。また、MetaTrader 5のストラテジーテスターを用いたテストと最適化の重要性についても取り上げ、EAが実際の取引環境に適応できるようにするプロセスを強調しました。自動売買であるとはいえ、その開発手法は手動取引戦略の構築プロセスに非常に近いものです。
免責条項:この記事で説明されている情報は、あくまでも教育目的です。これは、「プライスアクション手法に基づく高速戦略EA」の開発に関する考え方や洞察を提供するものです。最適化やデータ抽出をさらに取り入れて、より高性能なEAを構築するための出発点としてご活用ください。提示された情報は、いかなる取引結果も保証するものではありません。
この記事が役に立ち、楽しく、理解しやすく、今後のEAの開発に活かせるようなものであったことを願っています。今回の内容を通じて、プライスアクションアプローチ、特に高速取引戦略に基づく市場分析が、より身近で効果的なものになることを期待しています。お楽しみください。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/15698





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索