—————
改めて前回の内容をおさらいをしておくと、
- 待機注文の削除をするには メンバ変数 .actionに設定する定数値をTRADE_ACTION_REMOVE にする。
- 待機注文の削除は、.actionへの設定をTRADE_ACTION_REMOVEにしてしまえば、他に埋めるべきメンバ変数は、オーダー番号を格納する.orderだけである。
ということをお伝えしました。
今回から、いよいよ簡単な仕組みのEA(自動売買プログラム)を実際に作っていきたいと思います
今回の記事を読むことによって、今までの知識がどのような形でEA(自動売買プログラム)作成で利用されるのかを実感できるだけでなく、念願のEA作成がついにできるようになる訳です。
言うまでもなく、利益が出るような類のEAではなく、あくまでこれまでの知識を活かせばEAが作れることを示すためのものではありますが、是非楽しみにお読み頂ければと思います。
さて、今回作るEA(自動売買プログラム)の仕様は以下の通りです。
- 保有するポジションは1つまで。
- 売買判断には単純移動平均(SMA)を用いる
- 現在値が単純移動平均(SMA)を上回っていて、ポジションが0の時に買いエントリーする。
- 現在値が単純移動平均(SMA)を下回っていて、ポジションが0の時に売りエントリーする。
- ストップロスとテイクプロフィットをパラメータで設定できるようにする。
- 単純移動平均(SMA)の期間とボリューム(ロット数)もパラメーターで設定できるようにする。
※EA(自動売買プログラム)を運用するのは現在大半のブローカーが採用しているヘッジングシステム口座を想定して記述していきます。
ネッティングシステムとヘッジングシステムについては↓
MQL5 EA講座 第57回「ネッティングとヘッジング」 をご覧ください。
ステップ1:MQL5ウィザードを起動し、EAのひな型ファイルを作成する
「え?そこから?」という所から、説明をしていきますが、
MT5用EA(自動売買プログラム)を作るにあたっては、メタエディターの「新規作成」ボタンを押して、MQL5ウィザードを立ち上げ、「エキスパートアドバイザー(テンプレート)」を選択→EAの名前を決めます。
イベントハンドラーは、なにもチェックを入れずに完了させます。
詳しい手順については↓の記事をご覧ください。
これをたたき台にしてEA(自動売買プログラム)を作っていきます。
ステップ2:デモ口座でしか機能しない回路を盛り込む
これから作るEA(自動売買プログラム)は、利益を保証するものでは当然ありません。あくまで学習用です。従ってデモ口座でのみ稼働するような回路をOnInit関数に組み込みます。
int OnInit()
{
ENUM_ACCOUNT_TRADE_MODE tradeMode=(ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE);
if(tradeMode != ACCOUNT_TRADE_MODE_DEMO) // デモ口座以外の場合
{
MessageBox("このEAはデモ口座でのみ稼働します","口座エラー");
return INIT_FAILED; // 処理終了
}
//---
return(INIT_SUCCEEDED);
}
AccountInfoInteger関数の引数にACCOUNT_TRADE_MODEを記述すると、口座がリアル口座かデモ口座かを調べることができます。取得した値がデモ口座ではなかった場合、↓の動画のように処理を終了させます。
※ちなみにMQL4だとIsDemo関数という関数が、デモ/リアル口座の切り分けに使えましたが、MQL5ではIsDemo関数はなくなっています。
※OnInit関数については↓の記事をご覧ください。
MessageBox関数については↓の記事をご覧ください。
ステップ3:必要なパラメーターをinput変数で用意する
仕様で、
- ストップロスとテイクプロフィットをパラメータで設定できるようにする。
- SMAの期間とボリューム(ロット数)もパラメーターで設定できるようにする。
という事を決めたので、必要なパラメーターを記述します。
パラメータはグローバル領域(関数の外の領域にて設定します)に、input変数で用意します。
//+------------------------------------------------------------------+
//| testEA1.mq5 |
//| MQL5ssei |
//| https://mqlinvestmentlab.com/ |
//+------------------------------------------------------------------+
#property copyright "MQL5ssei"
#property link "https://mqlinvestmentlab.com/"
#property version "1.00"
//必要なパラメータ
input double Volume=1.0;//ロット数
input int SL=500;//ストップロス
input int TP=500;//テイクプロフィット
input int MAPeriod = 20;//移動平均期間
まだ売買記述は一切していませんが、この時点でコンパイルしてプログラムをチャートに挿入すると、
パラメータをいじることができるようになっています。↓
ステップ4:必要なグローバル変数を用意する
input変数の設定が終わったら、次はグローバル変数の記述に移ります。パラメータ化しない変数ですね。
今回作るEA(自動売買プログラム)は最大で1つしかポジションを保有しない仕様なので、その制御を行います。
ポジションを最大1つに制限する制御方法は色々な記述方法があるかと思いますが、今回はbool型のグローバル変数を使って制御したいと思います。
//直近の注文状況をチェックするグローバル変数
bool BuyPosition, SellPosition;
変数 「BuyPosition」、「SellPosition」の働きについては後程実際に使う段階で詳しく書きますが、BuyかSellどちらかの方向に直近ポジションを持っていたかを判断するbool型の変数になります。
直近にポジションを持った方がtrue、 持っていない方はfalseとなるように記述していきます。
例えば直近にBuyポジションを持ったら、変数BuyPositionがtrueになり、変数SellPositionがfalseとなる・・・といった感じです。
input変数、グローバル変数の設定が終わったので次は、OnTick関数内の記述に移ります。
ステップ5:OnTick関数内の記述
MqlTradeRequest構造体とMqlTradeResult構造体のインスタンス生成
まず最初に、MqlTradeRequest構造体とMqlTradeResult構造体のインスタンスを生成する記述を行います。
MqlTradeRequest構造体とMqlTradeResult構造体のインスタンス生成は、トレードサーバーに注文を出す役割を担うOrderSend関数の引数となるものなので、EA(自動売買プログラム)作成には必須の作業です。
MqlTradeRequest構造体とMqlTradeResult構造体、OrderSend関数の関係は以下の↓図のようになっています。
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
↑requestというMqlTradeRequest構造体をデータ型にしたインスタンスと、resultというMqlTradeResult構造体をデータ型にしたインスタンスができました。
ZeroMemory関数について
ZeroMemory関数は引数に変数やインスタンスを記述することで、記述した変数やインスタンスの値をゼロにリセットする機能を担っています。
※MqlTradeRequest構造体については→コチラをご覧ください。
※MqlTradeResult構造体については→コチラをご覧ください。
フィルポリシーを設定する関数を作り、メンバ変数.type_fillingに代入する
グローバル領域(関数の外の領域)に、適切なフィルポリシーを返す関数を作成します。
※「関数を作るってそもそもどういうこと?」という方は
第25回「関数について」をご覧ください。
//グローバル領域
//フィルポリシーを返す関数
ENUM_ORDER_TYPE_FILLING FillPolicy()
{
long fillType = SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);
if(fillType==SYMBOL_FILLING_IOC)return ORDER_FILLING_IOC;
else if(fillType==SYMBOL_FILLING_FOK)return ORDER_FILLING_FOK;
else return ORDER_FILLING_RETURN;
}
↑作った関数の中身を簡単に説明すると、まず
フィルポリシーを返す関数なので、戻り値のデータ型はENUM_ORDER_TYPE_FILLING となっています。
SymbolInfoInteger関数の第2引数にSYMBOL_FILLING_MODEを記述して取得した値を変数fillTypeに格納します。そこで獲得したフィルポリシーを戻り値として返すようになっています。
※フィルポリシーについては↓の記事をご参照ください。
作ったフィルポリシー関数を、メインプログラムであるOnTick関数内で、呼び出しメンバ変数 .type_filling に値を代入します。
//フィルポリシーを設定する。
request.type_filling=FillPolicy();
今解説しているEA(自動売買プログラム)ではOnTick関数内で埋めていますが、クラスを使うようになったらOnInit関数で埋める記述を紹介していきます。
単純移動平均線(SMA)の値を取得する記述を行う。
今回のEA(自動売買プログラム)は単純移動平均(SMA)をもとに、エントリー判断を行うので、単純単純移動平均(SMA)の値を取得する記述を行います。
// 単純移動平均の値取得
//単純移動平均の値を格納する配列宣言
double sma[];
//配列を時系列にセット
ArraySetAsSeries(sma,true);
//単純移動平均のハンドルを取得
int smaHandle=iMA(_Symbol,0,MAPeriod,MODE_SMA,0,PRICE_CLOSE);
///単純移動平均の値を配列にコピー
CopyBuffer(smaHandle,0,0,1,sma);
MQL4とは違い、MQL5では各種インジケータの値取得が組み込み関数だけでは完結しません。
- インジケータの値を格納する配列の宣言
- 組み込みインジケータ 関数によるハンドル(インジケータの値を取得する鍵のようなもの)の取得
- ArraySetAsSeries関数による、配列の時系列セット
- CopyBuffer関数による、インジケータの値情報を配列にコピー
以上のようなプロセスをたどる必要があります。
図にすると↓のような感じになります。
double型の配列 sma[]は、単純移動平均(SMA)の値を格納する為に用意されたものです。
ArraySetAsSeries関数は、第1引数に指定した動的配列に 時系列設定を付与することができる関数です。第2引数には時系列の設定フラグをtrueかfalseで設定します。
trueにすると、第1引数に指定した配列には直近の時間のデータから、配列に格納されていきます。配列[0]には最新の時間のデータが格納される、ということになります。
array[0](一番新しい時間)→・・・array[n](古い方の時間)という形です。
例えば5本分の足があったとして、[0]が一番新しく、[4]が一番古い・・・ということになります。↓
逆にfalseにした場合、配列は古い時間のデータから、配列に格納されていきます。配列[0]には取得されたデータ中で一番古い時間のデータが格納される、ということになります。
array[0](一番古い時間)→・・・array[n](新しい方の時間)
例えば5本分の足があったとして、[4]が一番新しく、[0]が一番古い・・・ということになります。↓
ArraySetAsSeries(sma,true);というのは、配列smaに、データを新しい順に格納していく、という事を意味しています。
※ArraySetAsSeries関数については→コチラをご覧ください。
iMA関数について
int iMA(
string symbol, // 銘柄名
ENUM_TIMEFRAMES period, // 期間
int ma_period, // 平均期間
int ma_shift, // 水平シフト
ENUM_MA_METHOD ma_method, // 平滑化の種類
ENUM_APPLIED_PRICE applied_price // 適用価格の種類
);
戻り値は指標ハンドル
第1引数には銘柄を指定する
第1引数には銘柄を指定します。定義済み変数「_Symbol」を記述すると、プログラムを挿入したチャートの銘柄を指定したことになります。
第2引数には時間軸を指定する
第2引数には時間軸を指定します。5分足なのか、1時間足なのか、日足なのか・・・そういう移動平均線を計算するベースとなるタイムフレームの指定です。定数値ENUM_TIMEFRAMESで定められた値を設定します。0、もしくはPERIOD_CURRENTと記述すると現在のチャートの時間軸が適用されます。
第3引数には移動平均を計算する期間を指定する
第3引数には移動平均線を計算する期間を指定します。例えば、ここに「20」と記述すれば、20期間の移動平均値が算出されることになります。今回作るEA(自動売買プログラム)の場合、最初に述べた通りここはinput変数「MAPeriod」で調整できるようにしてあります。
第4引数には、計算した移動平均の値をどれくらいずらして表示するか、を指定する
第4引数には、計算した移動平均線の値をどれくらいずらして表示するか、を指定します。
移動平均線のインジケータを挿入する時の、プロパティ「シフト」箇所にあたります。
指定した期間だけ、未来方向にずれて描画されます。
マイナス記号をつけると、指定した期間だけ過去方向にずれて描画されます。↓の動画は移動平均線のインジケータをチャートに挿入し、プロパティ「シフト」箇所(=iMA関数の第4引数にあたる部分)を変更している模様です。
最初にチャートに挿入した時は、シフトは「0」でした。その後、「10」に変更したところ、10期間分未来方向にずれて描画されています。一方、「-10」に変更したところ、10期間分過去方向にずれて描画されているのがわかると思います。
第5引数には移動平均平滑化の種類を指定する
移動平均線にもいくつかの種類があるため、それを選択する必要があります。
移動平均線の種類は、定数値ENUM_MA_METHODで定められたものを設定します。
今回は単純移動平均(SMA)を採用するので、MODE_SMAを記述しています。
※移動平均線の種類は単純移動平均(SMA)、指数平滑移動平均(Exponential Moving Average, EMA)、線形加重移動平均(Weighted Moving Average, WMA)があります。
詳しくは↓の記事で解説をしておりますので、宜しければご覧ください。
第6引数には適用価格の種類を指定する
第6引数には 適用価格の種類 を指定します。移動平均線を計算する際に、どの価格をベースするかを決めます。適用価格の種類は定数値ENUM_APPLIED_PRICEの中から設定します。今回はPRICE_CLOSE(終値)を記述します。
以上を踏まえてiMA関数の引数を埋めていくと以下のようになります。↓
//単純移動平均のハンドルを取得
int smaHandle=iMA(_Symbol,0,MAPeriod,0,MODE_SMA,PRICE_CLOSE);
int型の変数「smaHandle」はiMA関数が戻り値として返すハンドル値を格納する為に用意したものです。iMA関数に限らず、MQL5の組み込みインジケータ 関数はこのハンドル値を獲得する役割を担っています。このハンドル値を使って、さらにこれから説明するCopyBuffer関数を使って、移動平均線の値を取得します。
MQL4のように直接インジケータの値を返さないので注意が必要です。
ちなみに、MQL4のiMA関数の引数構成と戻り値は↓のようになっています。
double iMA(
string symbol, // 銘柄名
int timeframe, // 期間
int ma_period, // 平均期間
int ma_shift, // 水平シフト
int ma_method, // 平滑化の種類
int applied_price, // 適用価格の種類
int shift // 価格を取得する位置
);
戻り値は、引数「shift」で指定した位置の移動平均価格
CopyBuffer関数を使って、移動平均の値情報を配列にコピーする。
iMA関数を使い、晴れて単純移動平均(SMA)のハンドル値を取得出来たら、次はCopyBuffer関数を使って、単純移動平均(SMA)の値情報を配列sma[]にコピーします。
///単純移動平均の値を配列にコピー
CopyBuffer(smaHandle,0,0,10,sma);
CopyBuffer関数について
CopyBuffer関数は指定されたインディケータのバッファデータ(保存領域に格納されているデータ)を任意の配列にコピーしてくれる関数です。
CopyBuffer関数の引数と戻り値の構成は以下のようになっています。
(CopyBuffer関数は3つの書式をもつオーバーロード関数ですが、公式リファレンスにある第1書式のみ引用します)※オーバーロード関数については→コチラをご覧ください。
int CopyBuffer(
int indicator_handle, // 指標ハンドル
int buffer_num, // 指標バッファ番号
int start_pos, // 開始位置
int count, // 複製する量
double buffer[] // 受け取り側の配列
);
戻り値は複製されたデータ数(エラーの場合は -1 )
第1引数には指標ハンドルを指定する
第1引数には指標ハンドルを指定します。iMA関数にて取得した値を変数「smaHandle」に格納しているので、変数「smaHandle」を記述します。
第2引数にはバッファ番号を指定する
バッファ番号とは?
プログラミングの世界では、バッファという言葉は保存領域という文脈で使われるので、インジケータのバッファデータは、「インジケータの値のデータ」と読み替えれば問題ないかと思います。
インジケータによってはバッファデータが1つしかないものと、複数で構成されているものもあります。
バッファデータが1つしかないインジケータのことをシングルバッファインジケータと呼びます。
移動平均線やモメンタムなどはシングルバッファインジケータにあたります。
バッファデータが複数で構成されているインジケータの事をマルチバッファインディケータと呼びます。
ボリンジャーバンドやストキャスティクス、MACDなどがマルチバッファインディケータに該当します。それぞれのインジケータのバッファデータ数に応じて、バッファ番号というものが割り振られています。
今回第2引数に割り当てるバッファ番号ですが、移動平均線はバッファデータを1つしか持たないシングルバッファインジケータなので、0を記述します。
第3引数には、コピー開始位置を指定する
第3引数には、コピー開始位置を指定します。インジケータのバッファデータは、最新のデータが0番に格納され、時間軸が古い方に向かって、1.2.3・・・n番目と並んでいます。
今回は最新足のデータからコピーをしたいので0を記述します。
第4引数には複製データ数を指定する
第4引数には複製データ数を指定します。第3引数で指定したコピー開始位置から指定した数だけバッファデータをコピーします。例えば第4引数に「10」と記述し、第3引数に「0」と記述した場合、最新足から10期間分のバッファデータが配列にコピーされます。
今回作るEA(自動売買プログラム)は、最新足の移動平均値だけ使う予定なので、第4引数には「1」を記述しています。
第5引数には複製データ数をコピーする配列を指定する
第5引数には複製データ数をコピーする配列を指定します。注意したいのが、第1引数から第4引数までは入力データを記述していましたが、第5引数は出力データを記述しているということです。
第1引数から第4引数までが注文伝票であり、注文した商品を第5引数で受け取るイメージです。
MQL5公式リファレンスで関数の働きを調べるときは、各引数が入力(input)なのか、出力(output)なのか、という部分も注意深く見る必要があります。公式リファレンスのCopyBuffer関数ページにおけるパラメータ部分を見ると↓
パラメータ
indicator_handle
[in] 対応する指標関数によって戻された指標ハンドル
buffer_num
[in] 指標バッファの番号
start_pos
[in] 1 番目の複製される要素の位置
count
buffer[]
[out] double 型の配列
[in]と書かれている引数は入力、[out]と書かれている引数は出力の働きをすることを示しています。
公式リファレンスの関数ページの見方については↓の記事もご参照ください。
※CopyBuffer関数は以下の記事でも記述例・使用例が確認できますので、よろしければ参考にしていただければと思います。↓
——————————————————-
・MQL5 EA講座 第98回「動的トレーリングストップについて」
・【MQL5入門】ウィリアムズ%レンジ(WPR)の売買シグナルを取得する方法【EAの作り方】
・【MQL5入門】モメンタムの売買シグナルを取得する方法【EAの作り方】
・【MQL5でパラボリックSARの売買シグナルを取得する方法】
・【MQL5でストキャスティクスの売買シグナルを取得する方法】
・【MQL5】5分で書ける、パーフェクトオーダーの記述【EAの作り方】
——————————————————-
ここまでで、EA(自動売買プログラム)の売買判断基準にする予定の、移動平均線に関する値取得の記述が完了しました。
今回は一旦ここまでとしたいと思います。<m(__)m>
ここまでの記述内容全体
ここまでの記述内容は以下の通りです↓
//+------------------------------------------------------------------+
//| testEA1.mq5 |
//| MQL5ssei |
//| https://mqlinvestmentlab.com/ |
//+------------------------------------------------------------------+
#property copyright "MQL5ssei"
#property link "https://mqlinvestmentlab.com/"
#property version "1.00"
//必要なパラメータ
input double Volume=1.0;//ロット数
input int SL=500;//ストップロス
input int TP=500;//テイクプロフィット
input int MAPeriod = 20;//移動平均期間
//直近の注文状況をチェックするグローバル変数
bool BuyPosition, SellPosition;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
ENUM_ACCOUNT_TRADE_MODE tradeMode=(ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE);
if(tradeMode != ACCOUNT_TRADE_MODE_DEMO) // デモ口座以外の場合
{
MessageBox("このEAはデモ口座でのみ稼働します","口座エラー");
return INIT_FAILED; // 処理終了
}
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
//フィルポリシーを設定する。
request.type_filling=FillPolicy();
// 単純移動平均の値取得
//単純移動平均の値を格納する配列宣言
double sma[];
//配列を時系列にセット
ArraySetAsSeries(sma,true);
//単純移動平均のハンドルを取得
int smaHandle=iMA(_Symbol,0,MAPeriod,0,MODE_SMA,PRICE_CLOSE);
///単純移動平均の値を配列にコピー
CopyBuffer(smaHandle,0,0,10,sma);
}
//+---
//グローバル領域
//フィルポリシーを返す関数
ENUM_ORDER_TYPE_FILLING FillPolicy()
{
long fillType = SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);
if(fillType==SYMBOL_FILLING_IOC)return ORDER_FILLING_IOC;
else if(fillType==SYMBOL_FILLING_FOK)return ORDER_FILLING_FOK;
else return ORDER_FILLING_RETURN;
}
まとめ
今回は 簡単な仕組みのEA(自動売買プログラム)作り第1弾をお届けしました。
今回の記事では以下の作業を行いました。
- MQL5ウィザードを起動し、EA(自動売買プログラム)のひな型ファイルを作成する
- デモ口座でしか機能しない回路を盛り込む
- 必要なパラメーターをinput変数で用意する
- 必要なグローバル変数を用意する
- 単純移動平均(SMA)の値を取得する記述を行う。
今回は以上になります。次回は引き続きEA(自動売買プログラム)を作っていきます。エントリー条件などの記述を行っていく予定です。
最後までお読みいただきありがとうございました<m(__)m>
コメント