「10時にエントリーして12時に決済する」という単純な時間指定EAのサンプルコードをそのまま使うと、同じ口座で他のEAや裁量トレードを1つでも動かしていた場合に、狙った時刻でエントリーできなくなったり、逆に無関係な注文を決済しようとしてエラーになったりすることがあります。
原因は、ポジションの有無を「口座全体の注文数」だけで判定しており、自分(このEA)が出した注文かどうかを区別していないことです。この記事では、指定した時刻にエントリー・決済するEAの作り方を、他のEAと共存できる形に直したうえで解説します。
ある時間にポジションをエントリーして決済するEA
ある時間にポジションをエントリーして決済するEAを作成したいと思います。
- 10時にエントリーする
- 12時に決済する
- SLなし
- TPなし
という感じで作っていきます。
メタエディタ(MetaEditor)を立ち上げる
MT4を起動し、ツールバーの黄色いボタン(またはツール→MetaQuotes Language Editor)からメタエディタ(MetaEditor)を立ち上げましょう。
新しいEAを作るので、メタエディタの「ファイル」→「新規作成」を選び、ウィザードで「Expert Advisor(テンプレートを使用)」を選択して「次へ」を押します。名前を入力する画面が出るので、今回は「10-12Hour」と入力します(作者名・リンク・バージョンは空欄のままで問題ありません)。あとの画面はそのまま「次へ」を数回押して「完了」まで進めると、OnInit()・OnDeinit()・OnTick()の3つの関数だけが最初から書かれた空のひな形が開きます。
パラメーターを記述する
パラメーターを記述しましょう。
input double LOT = 0.01;//ロット input int SLIP = 1;//スリッページ input int MAGIC = 12345;//マジックナンバー
自分のポジションを判定する関数を用意する
自分(このEA、マジックナンバー)が出した注文のチケット番号を、その都度検索して取得する関数を用意しましょう。
元のコードのようにグローバル変数`TicketNumber`だけで管理すると、口座に他のEA・裁量トレードのポジションがあった場合に、それらの数まで数えてしまい、狙った時刻でエントリーできない・無関係な注文を決済しようとしてエラーになる、といった不具合につながります。
int GetMyTicket()
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGIC)
return(OrderTicket());
}
return(-1);
}
保有中の注文を1件ずつ確認し、通貨ペアとマジックナンバーが一致する注文が見つかればそのチケット番号を、見つからなければ-1を返します。
OnTick()関数を記述する
OnTick()関数を記述しましょう。10時にエントリーしたいので、
まず`GetMyTicket()`で自分の注文の有無を確認し、まだ注文がなければHour()で10時を指定します。
int ticket = GetMyTicket(); if(ticket < 0 && Hour() == 10)
※`Hour()`が返すのは、パソコンやスマホの現地時間ではなく、MT4のチャートに表示されているサーバー時間です。ブローカーによってサーバー時間の基準(GMT+2やGMT+3など)が異なるため、「日本時間の10時」ではなく「使っているMT4のサーバー時間で10時」になる点に注意してください。何時間ズレているかは、MT4の気配値表示ウインドウやチャート右下の時刻表示で確認できます。
そして、条件が満たされていれば、ポジションを取ります。
int result = OrderSend(Symbol(), OP_BUY, LOT, Ask, SLIP, 0, 0, "BUY", MAGIC, 0, clrRed);
if(result < 0)
Print("買い注文に失敗しました。エラーコード=", GetLastError());
同様な手順で、次に時間が12時になったら、自分の注文を選択して決済します。
if(ticket >= 0 && Hour() == 12)
{
if(OrderSelect(ticket, SELECT_BY_TICKET))
{
bool closed = OrderClose(ticket, OrderLots(), Bid, SLIP, clrDodgerBlue);
if(!closed)
Print("決済に失敗しました。エラーコード=", GetLastError());
}
}
元のコードは決済時のロット数に`LOT`パラメーター(入力値)をそのまま使っていましたが、ここでは`OrderLots()`で実際に保有しているロット数を取得して指定しています。手動で一部だけ決済した場合など、保有ロットと入力値がずれるケースにも対応できます。
これでOnTick()関数の記述は完了です。
int ticket = GetMyTicket();
//オーダーがなく時間が10時である場合
if(ticket < 0 && Hour() == 10)
{
int result = OrderSend(Symbol(), OP_BUY, LOT, Ask, SLIP, 0, 0, "BUY", MAGIC, 0, clrRed);//ロングエントリー
if(result < 0)
Print("買い注文に失敗しました。エラーコード=", GetLastError());
}
//オーダーがあり時間が12時である場合
if(ticket >= 0 && Hour() == 12)
{
if(OrderSelect(ticket, SELECT_BY_TICKET))
{
bool closed = OrderClose(ticket, OrderLots(), Bid, SLIP, clrDodgerBlue);//ポジションを決済
if(!closed)
Print("決済に失敗しました。エラーコード=", GetLastError());
}
}
損切り・利確を設定しない場合のリスクについて
この記事のEAは、最初の仕様どおり損切り(SL)・利確(TP)を設定していません。「12時になったら決済する」というロジックだけでポジションを管理しています。
これは、もし何らかの理由(サーバー接続断・OrderCloseの失敗が続く等)で12時の決済が実行できなかった場合、損切りによる歯止めがないまま含み損が広がり続けることを意味します。学習用として動かす場合も、決済が正しく行われているかをターミナルの「取引」タブで必ず確認してください。実際の口座で稼働させる場合は、OnTick()に損切り注文を追加するか、緊急時用のストップロスを別途設定することを検討してください。
コンパイル
コンパイルして動きを確認しましょう。10時にエントリーして12時に決済されていたら完了です。

ソースコード全体
ここまでの修正をすべて反映した、実際にMetaEditorでコンパイルしてそのまま動かせる状態のコードです。
//+------------------------------------------------------------------+
//| 10-12Hour.mq4 |
//| Copyright 2020, FX-EA System Project Creator |
//| https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, FX-EA System Project Creator"
#property link "https://creator.fx-ea-system-project.com/"
#property version "1.01"
#property strict
/*パラメーター*/
input double LOT = 0.01;//ロット
input int SLIP = 1;//スリッページ
input int MAGIC = 12345;//マジックナンバー
//+------------------------------------------------------------------+
//| このEA(マジックナンバー)のポジションのチケット番号を取得する |
//+------------------------------------------------------------------+
int GetMyTicket()
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGIC)
return(OrderTicket());
}
return(-1);
}
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
int ticket = GetMyTicket();
//オーダーがなく時間が10時である場合
if(ticket < 0 && Hour() == 10)
{
int result = OrderSend(Symbol(), OP_BUY, LOT, Ask, SLIP, 0, 0, "BUY", MAGIC, 0, clrRed);//ロングエントリー
if(result < 0)
Print("買い注文に失敗しました。エラーコード=", GetLastError());
}
//オーダーがあり時間が12時である場合
if(ticket >= 0 && Hour() == 12)
{
if(OrderSelect(ticket, SELECT_BY_TICKET))
{
bool closed = OrderClose(ticket, OrderLots(), Bid, SLIP, clrDodgerBlue);//ポジションを決済
if(!closed)
Print("決済に失敗しました。エラーコード=", GetLastError());
}
}
}
//+------------------------------------------------------------------+
バックテストで動作を確認する
コードを保存したら、MetaEditorの「コンパイル」(Ctrl+F7)で「0 error(s), 0 warning(s)」になることを確認します。
そのあとMT4の「表示」→「ストラテジーテスター」を開き、Expert Advisorに作成した10-12Hourを選択、通貨ペアと期間を指定して、モデルを「全ティック(最も正確な値)」にしてスタートすると、過去データでの動作を確認できます。10時にエントリーし、12時に決済されているかを、結果の「取引履歴」タブで確認してください。
実運用する前に確認しておきたいこと
このEAは時間帯だけでエントリー・決済を判断する、学習用にシンプルへ作った例です。実際の口座で稼働させる前に、次の点を確認してください。
- 損切り・利確を設定していないため、決済処理が失敗すると含み損が無制限に広がるリスクがある
- 10時〜12時の間にトレンドが急変した場合の値動きは考慮していない
- 土日・祝日をまたぐ時間帯や、サーバー時間と自分のいる時間帯のズレは検証していない
まずはデモ口座、または少額のロットでのフォワードテストを行ってから、本番運用を検討してください。
まとめ
これで時間指定の条件でEAを制御することができましたね。マジックナンバーで自分のポジションだけを正確に判定できるようにしたことで、他のEAや裁量トレードと同じ口座でも安心して動かせる形になりました。
コメント