HMC-EAのソースコード全文(MQL5によるMT5用EAのサンプルコード)
この記事では、MT5用のハイブリッド・モンテカルロEA(HMC-EA)のソースコードを全文掲載しています。
内容をコピペするだけで、MT5用のHMC-EAをMQL5で作成することが可能です。なお、それぞれのコードの説明も可能な限り細かく記載していますで、これをベースにご自身でロジックをお好きなようにカスタマイズしていただくこともできます。
また、最後にこの記事で紹介したコードをまとめたmq5ファイルをダウンロード可能にしております。このファイルをただコンパイルするだけでも、ex5ファイル(EAの実行ファイル)を作成することができますので、EAとしてそのまま使用していただくことも可能です。
MQL5でFX自動売買
FXの自動売買というと、MT4やMT5で使用されるMQL4やMQL5という言語で構築したEA(エキスパートアドバイザー)が一般的です。かつてはMT4が主流でMT5が登場してもなかなか移行が進まなかったのですが、最近はMT5の方が主流になりつつあります。MT5の方がMT4よりも動作スピードが速く、バックテストも行いやすかったりと、様々なメリットが溢れています。初心者が本気で始めるとしたらMT4よりもMT5が良いということも言えます。
HMC-EA(ハイブリッド・モンテカルロEA)とは
以下のページでロジックを詳細解説しているEAです。
このHMC-EAについて、「MQL5でこの売買戦略を実装するためのコード」を以下ではご紹介していきます。
MQL5でロジック実装する上で必要なコードを詳細まで掲載していますので是非ご確認ください。少し複雑な処理も組み合わせたロジックになっていますので、MT5で他のEAを開発する際にも参考になるコードがあったりすると思います。
プロパティ設定や変数の宣言と初期化
ここからコードの解説に入ります。まずは、プログラム全体の前提となる初期設定部分です。
プロパティ設定
#property copyright "Copyright 2024, nanpin-martin.com"
#property link "https://nanpin-martin.com/"
#property version "1.00"
例えば、上記のように記載するとEAの表示が以下のような画面になります。
Input設定
初期設定として、いくつかインプットを定めておきます。
input int EA_type = 5;//1:NM, 2:NMC, 3:AM, 4:AMC, 5:HMC
input int mode_type = 2;//1:Static, 2:Dynamic
input double range_input = 5;//基準幅
input double lot_size = 0.01; // ロット数
input double martin_factor = 2.0; // マーチン倍率(NMまたはAMのみ有効)
input int max_position = 80;//最大ポジション数
input double spread_limit = 20;//許容スプレッド(point)
input int magic_number = 10001;//マジックナンバー
「input~」と記載することで、EA利用時にユーザーが指定可能な変数になります。各インプットの内容は、以下の記事にて詳しく説明していますのでご参照ください。
その他の初期設定
以下の変数を定義しておきます。いずれも、後述の処理で登場します。
ulong slippage = 10; // スリッページ
int anti_mode = 0;
int anti_position = 2;
int mode_target = 8;
double current_range;
int period1 = 120;//Dynamic1(分)
int period2 = 30;//Dynamic2(分)
datetime last_decision_time = TimeCurrent();
int reset_interval_1 = 30;//値幅をリセットする間隔1(分)
int reset_interval_2 = 30;//値幅をリセットする間隔2(分)
int x,y,z;
int buy_lot_array[100];
int sell_lot_array[100];
int current_buy_lot_array;
int current_sell_lot_array;
int buy_position, sell_position;
int buy_entry_cnt, buy_close_cnt, sell_entry_cnt, sell_close_cnt;
int buy_target, sell_target;
double Ask, Bid, Spread, current_price, base_price;
int OnInit()
ここからは、初期化関数であるint OnInit()内に書かれる処理です。
int OnInit()
{
base_price_load();
current_range_load();
buy_lot_array_load();
sell_lot_array_load();
set_current_buy_lot_array();
set_current_sell_lot_array();
buy_target = current_buy_lot_array - 1;
sell_target = current_sell_lot_array - 1;
if(EA_type == 1 || EA_type == 2)
{anti_mode = 0;}
else
if(EA_type == 3 || EA_type == 4)
{anti_mode = 1;}
if(mode_type == 1)
{current_range = range_input;}
return(INIT_SUCCEEDED);
}
void OnTick()
ここからは、ティックイベント関数であるvoid OnTick()内に書かれる処理です。これは新しいティックが更新されるたびに行われる処理で、何度も繰り返すループ処理に近い動きをします。
コメント表示
以下のようなEA稼働中のコメントを表示するための処理です。
わかりやすくするための表示だけの処理ですので、実際のEA稼働には影響しません。
string message = " \n";
if(EA_type == 1)
{message += "NM-EA";}
else
if(EA_type == 2)
{message += "NMC-EA";}
else
if(EA_type == 3)
{message += "AM-EA";}
else
if(EA_type == 4)
{message += "AMC-EA";}
else
if(EA_type == 5)
{message += "HMC-EA";}
if(mode_type == 1)
{message += " Static\n";}
else
if(mode_type == 2)
{message += " Dynamic\n";}
string part_message = "\n";
part_message += "Spread: " + DoubleToString(Spread, 3)+"\n";
part_message += "\n";
part_message += "Current Price: " + DoubleToString(current_price, 3)+"\n";
part_message += "Base Price: " + DoubleToString(base_price, 3)+"\n";
part_message += "Current Range: " + DoubleToString(current_range, 3)+"\n";
part_message += "\n";
part_message += "Buy: [ " + IntegerToString(buy_lot_array[0]);
bool first_zero_encountered = false;
for(int i=1; i<100; i++)
{
if(buy_lot_array[i] == 0 && !first_zero_encountered)
{
first_zero_encountered = true;
}
if(buy_lot_array[i] == 0 && first_zero_encountered)
{
break;
}
else
part_message += ", " + IntegerToString(buy_lot_array[i]);
}
part_message += " ] --> ";
part_message += IntegerToString(current_buy_lot_array)+"\n";
part_message += "Sell: [ " + IntegerToString(sell_lot_array[0]);
for(int i=1; i<100; i++)
{
if(sell_lot_array[i] == 0 && !first_zero_encountered)
{
first_zero_encountered = true;
}
if(sell_lot_array[i] == 0 && first_zero_encountered)
{
break;
}
else
part_message += ", " + IntegerToString(sell_lot_array[i]);
}
part_message += " ] --> ";
part_message += IntegerToString(current_sell_lot_array)+"\n";
part_message += "\n";
part_message += "Target: " + IntegerToString(buy_target - sell_target)+"\n";
message += part_message + "\n";
Comment(message);
スプレッド判定
// Ask、Bidとスプレッドを取得
GetMarketInfo(_Symbol, Ask, Bid, Spread);
// スプレッドが許容スプレッドを超える場合は以降の処理をスキップ
if(Spread > spread_limit * Point())
return;
現在のスプレッドを計算し、指定した許容スプレッド(spread_limit)を超えている場合は、後続の処理は行わずに終了する処理です。スプレッドが拡大している時は予測や取引を含めて余計な処理は行わないようにします。
現在価格の取得およびモード判定
current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); // 現在の価格を取得
if(mode_type == 2 && MathAbs(buy_target - sell_target) < mode_target)
{ResetRange(current_range);}
else
{
if(current_range != range_input)
{
current_range = range_input;
current_range_record();
}
}
ここでは、モード判定を行なっています。このHMC-EAでは、Static(静的モード)とDynamic(動的モード)を選択可能な仕組みを採用しています。
Staticでは、常に基準幅が固定値で設定されます。Dyanamicでは、インプットで設定した基準幅をベースとしつつ、ヒストリカル・ボラティリティを考慮して動的に基準幅を変動させます。その初期設定です。
勝敗判定
HMC-EAでは、基準値(base-price)より、基準幅(current_range)だけ上昇あるいは下落した場合に勝敗の決着がつくことになります。
上昇と下落で勝敗を逆にするアンチ・マーチンゲールのようなタイプも選択できるようにしているので、その分岐も行なっています。
// 上昇判定
if(current_price >= base_price + current_range)
{
if(anti_mode == 0)
{
ProcessWin(current_price, buy_target, "buy", base_price);
ProcessLoss(current_price, sell_target, "sell", base_price);
}
else
{
ProcessLoss(current_price, buy_target, "buy", base_price);
ProcessWin(current_price, sell_target, "sell", base_price);
}
}
// 下落判定
if(current_price <= base_price - current_range)
{
if(anti_mode == 0)
{
ProcessLoss(current_price, buy_target, "buy", base_price);
ProcessWin(current_price, sell_target, "sell", base_price);
}
else
{
ProcessWin(current_price, buy_target, "buy", base_price);
ProcessLoss(current_price, sell_target, "sell", base_price);
}
}
NetTargets();
最後に「NetTargets」という関数を設定していますが、これは両建て戦略を導入して無駄なポジションを減らすための処理です。関数の内容はダウンロードファイルでご確認ください。
ポジションの確認
「CheckPositions」という関数を定義して現在保有しているbuyポジションおよびsellポジションの数を取得します。
また、HMC-EAではポジションの数に閾値を設定して、モンテカルロとアンチ・モンテカルロの切り替えを行うので、その判定を入れています。
// ポジションの確認
CheckPositions();
if(EA_type == 5)
{
if(buy_target >= anti_position || sell_target >= anti_position)
{anti_mode = 1;}
else
{anti_mode = 0;}
}
調整ロット数の確認
HMC-EAでは、勝敗判定結果によって、保有ポジションのターゲット数が決定されます。そのターゲット数と現在のポジション数の乖離を確認して、ポジション数を増やす必要があればエントリー注文を行い、減らす必要があればクローズ注文を行うことになります。その判定を行う処理です。
// 調整ロット数の確認
if(buy_target == buy_position && sell_target == sell_position)
return;
if(buy_target > buy_position)
{
buy_entry_cnt = buy_target - buy_position;
}
if(buy_target < buy_position)
{
buy_close_cnt = buy_position - buy_target;
}
if(sell_target > sell_position)
{
sell_entry_cnt = sell_target - sell_position;
}
if(sell_target < sell_position)
{
sell_close_cnt = sell_position - sell_target;
}
エントリー注文およびクローズ注文
エントリー注文およびクローズ注文を行う処理です。HMC-EAでは、判定結果によっては大量の注文を行うことになる可能性もあるので、エラー注文を繰り返しすぎたりしないような処理を念の為入れています。
// 注文エントリーの試行回数制限 (buy側)
int maxRetry = 5; // 最大試行回数を設定
int retryCounter = 0; // 試行カウンタ
while(buy_entry_cnt > 0 && retryCounter < maxRetry)
{
bool entry_sent = SendOrder(1, lot_size);
if(entry_sent)
{
buy_entry_cnt--; // 成功したのでカウンタを減少させる
break; // 成功したらループを抜ける
}
else
{
retryCounter++; // 試行カウンタを増やす
Sleep(1000); // 少し待ってから再試行
}
}
// 注文クローズの試行回数制限 (buy側)
retryCounter = 0; // カウンタをリセット
while(buy_close_cnt > 0 && retryCounter < maxRetry)
{
bool close_sent = CloseBuyPosition(); // 適切なClose関数を呼び出す
if(close_sent)
{
buy_close_cnt--; // 成功したのでカウンタを減少
break; // 成功したらループを抜ける
}
else
{
retryCounter++; // 試行カウンタを増やす
Sleep(1000); // 少し待ってから再試行
}
}
// 注文エントリーの試行回数制限 (sell側)
retryCounter = 0; // カウンタをリセット
while(sell_entry_cnt > 0 && retryCounter < maxRetry)
{
bool entry_sent = SendOrder(2, lot_size);
if(entry_sent)
{
sell_entry_cnt--; // 成功したのでカウンタを減少させる
break; // 成功したらループを抜ける
}
else
{
retryCounter++; // 試行カウンタを増やす
Sleep(1000); // 少し待ってから再試行
}
}
// 注文クローズの試行回数制限 (sell側)
retryCounter = 0; // カウンタをリセット
while(sell_close_cnt > 0 && retryCounter < maxRetry)
{
bool close_sent = CloseSellPosition(); // 適切なClose関数を呼び出す
if(close_sent)
{
sell_close_cnt--; // 成功したのでカウンタを減少
break; // 成功したらループを抜ける
}
else
{
retryCounter++; // 試行カウンタを増やす
Sleep(1000); // 少し待ってから再試行
}
}
}
以上でメイン処理は完了です。後はそれぞれの処理を行う関数を詳細に設定しているのみになります。
有料部分の内容
有料部分では、HMC-EAのロジックを全て盛り込んだmq5ファイル(MetaTrader5向けに書かれたプログラム)をダウンロード可能にしています。ただコンパイルするだけで、HMC-EA_note.ex5が作成可能ですので、特にいじらずにそのままEAとしても使用可能です。
上記の記事においてダウンロード可能な「HMC-EA.ex5」では、リアル口座では認証コードが必要になる制限がかかっています。しかし、この記事のmq5ファイルから作成した「HMC-EA_note.ex5」であれば、特に制限なくリアル口座でも利用可能です。制限なしでEAを使用するためにもご活用ください。
注意点
当記事で掲載しているコードはこちらの記事で紹介しているような環境でMT5のインストールが完了していて、必要な準備が整っている上での実行を想定しています。
記事執筆時点で稼働確認を行なっており、エラーが出ないことを確認しておりますが、その後の環境変化等で想定通りに稼働しない可能性はございます。動作保証等はいたしかねますのでご了承ください。
リアル口座にアクセスして取引を行うことも可能なコードになっておりますが、必ずデモ口座で事前に稼働確認をしていただくことを推奨いたします。
当記事や他記事で解説しているロジック通りの動作を保証するものではございません。あくまでEA(FX自動売買ツール)開発のためのサンプルコードとしてご活用ください。
この記事はMT5用です。MT4用EAについては、以下の別記事をご覧ください。
ここから先は
¥ 5,000
よろしければサポートお願いします。いただいたサポートは今後の記事の執筆に活用させていただきます。