ネットにあるRSI逆張りEAのサンプルコードをそのままMT4に入れて動かしたら、他のEAや裁量ポジションを持っているときだけ新規エントリーしなくなった、損切りされずに含み損が膨らみ続けた——MQLでEAを自作し始めた人がよくつまずくポイントです。
原因の多くは、「ポジションの有無」を口座全体の注文数で判定してしまっていることと、損切りの設定漏れです。この記事では、RSI(相対力指数)が70以上・30未満のときに逆張りエントリーするEAを例に、パラメーターの設定からOnTick()関数の中身、そして見落としがちな「自分のポジションだけを数える判定」と「損切り設定」まで、実際にMetaEditorでコンパイルしてMT4で動かせる状態のコードを最後まで解説します。
RSIが70以上か30未満で逆張りトレードするEA
RSIが70以上か30未満で逆張りトレードするEAを作成していきます。
メタエディタ(MetaEditor)を立ち上げる
MT4を起動し、ツールバーの黄色いボタン(またはツール→MetaQuotes Language Editor)からメタエディタ(MetaEditor)を立ち上げましょう。
メタエディタの「ファイル」→「新規作成」を選び、ウィザードで「Expert Advisor(テンプレートを使用)」を選択します。名前は今回「RSI-7030」と入力し、あとは「次へ」を数回押して「完了」まで進めてください。OnInit()・OnDeinit()・OnTick()の3つの関数だけが最初から書かれた空のひな形が開きます。
パラメーターを記述する
パラメーターを記述しましょう。今回は利確・損切り・ロット数・マジックナンバー・スリッページ・RSIの期間の6つを、あとから値を変更しやすいようにinput変数として用意します。
input int TakeProfit = 5;//利確(pips) input int StopLoss = 10;//損切り(pips) input double Lots = 0.01;//ロット数 input int MagicNumber = 12345;//マジックナンバー input int Slippage = 3;//スリッページ input int RSI_period = 14;//RSIの期間
損切り(StopLoss)とスリッページ(Slippage)は、後述する理由でこの記事から新しく追加したパラメーターです。
※このEAを動かして「エラーコード130(Invalid stops)」がログに出た場合、原因の多くはStopLoss・TakeProfitの値がブローカーの最小ストップ距離より近いことです。エラー130が出た場合は、まずStopLoss・TakeProfitの値を大きくしてみてください。
自分のポジションだけを判定するようにする
最初は1つのEAしか動かしていなくても、慣れてくると別の通貨ペアで別のEAを追加したり、裁量トレードのポジションを一時的に持ったりすることはよくあります。そのとき、RSIの逆張りは「今ポジションを持っていないこと」を確認してからエントリーする必要がありますが、この判定を`OrdersTotal()`(口座全体の保有注文数)だけで行うと、他のEA・裁量ポジションを1つ持っているだけで、このEAは新規エントリーの判定自体を行わなくなってしまいます。
このEA(マジックナンバー)自身のポジションをすでに持っているかどうかを判定する関数を用意し、OnTick()の先頭でチェックします。
bool HasPosition()
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber)
return(true);
}
return(false);
}
OrdersTotal()で保有中の注文数だけループし、通貨ペアとマジックナンバーが一致するポジションが1つでもあればtrueを返します。これで、他のEAや裁量ポジションに影響されず、このEA自身のポジションの有無だけを正しく判定できます。
OnTick()関数を記述する
OnTick()関数を記述しましょう。まず、先ほどのHasPosition()でポジションの有無を確認します。
if(HasPosition()) return;//既にポジションがあれば新規エントリーしない
次にRSIの値を取得します。
double rsi = iRSI(Symbol(),0,RSI_period,PRICE_CLOSE,0);
RSIが30を下回っていれば「売られすぎ」と判断してロングエントリーします。
if(rsi < 30)//RSIが30を下回ったら売られすぎと判断しロング
条件が合えば、ロングのポジションを持ちます。
OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,Ask-StopLoss*Point*10,Ask+TakeProfit*Point*10,"Order Long",MagicNumber,0,Lime);
RSIが70を上回っていれば「買われすぎ」と判断してショートエントリーします。
if(rsi > 70)//RSIが70を上回ったら買われすぎと判断しショート
条件が満たされていればショートのポジションを持ちます。
OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,Bid+StopLoss*Point*10,Bid-TakeProfit*Point*10,"Order Short",MagicNumber,0,Red);
これでエントリーのロジック自体はできましたが、最後にもう1つ、損切りの設定を確認しておきます。
損切り(ストップロス)を設定する
元のOrderSend()は、6番目の引数(損切り価格)が0になっていました。0を指定すると損切りは設定されず、RSIが逆行しても決済されないまま含み損が膨らみ続けます。
利確だけでなく損切りも必ず設定しましょう。パラメーターに追加したStopLossを使って、エントリー方向と逆側に損切りラインを計算します。
//買いの場合 Ask-StopLoss*Point*10 //売りの場合 Bid+StopLoss*Point*10
※Pointは通貨ペアの最小価格単位です。多くのFX業者が採用している5桁表示(例:USDJPYが150.123のように小数点以下3桁)のブローカーでは1pip=10Pointになるため、pips単位で指定したTakeProfit・StopLossに10を掛けています。4桁表示(USDJPYが150.12までの2桁)のブローカーを使う場合は、この「×10」を外してください。
ソースコード全体
ここまでの修正をすべて反映した、実際にMetaEditorでコンパイルしてそのまま動かせる状態のコードです。
//+------------------------------------------------------------------+
//| RSI-7030.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 int TakeProfit = 5;//利確(pips)
input int StopLoss = 10;//損切り(pips)
input double Lots = 0.01;//ロット数
input int MagicNumber = 12345;//マジックナンバー
input int Slippage = 3;//スリッページ
input int RSI_period = 14;//RSIの期間
//+------------------------------------------------------------------+
//| このEA(マジックナンバー)のポジションを保有しているか判定する |
//+------------------------------------------------------------------+
bool HasPosition()
{
for(int i=OrdersTotal()-1; i>=0; i--)
{
if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber)
return(true);
}
return(false);
}
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
//既にポジションを持っている場合は新規エントリーしない
if(HasPosition())
return;
double rsi = iRSI(Symbol(),0,RSI_period,PRICE_CLOSE,0);
int ticket;
if(rsi < 30)//RSIが30を下回ったら売られすぎと判断しロング
{
ticket = OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,Ask-StopLoss*Point*10,Ask+TakeProfit*Point*10,"Order Long",MagicNumber,0,Lime);
if(ticket < 0)
Print("買い注文に失敗しました。エラーコード=",GetLastError());
}
if(rsi > 70)//RSIが70を上回ったら買われすぎと判断しショート
{
ticket = OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,Bid+StopLoss*Point*10,Bid-TakeProfit*Point*10,"Order Short",MagicNumber,0,Red);
if(ticket < 0)
Print("売り注文に失敗しました。エラーコード=",GetLastError());
}
}
//+------------------------------------------------------------------+
バックテストで動作を確認する
コードを保存したら、MetaEditorの「コンパイル」(Ctrl+F7)で「0 error(s), 0 warning(s)」になることを確認します。
そのあとMT4の「表示」→「ストラテジーテスター」を開き、Expert AdviserにRSI-7030を選択、通貨ペアと期間を指定して、モデルを「全ティック(最も正確な値)」にしてスタートすると、過去データでの動作を確認できます。
他のEAや裁量ポジションを持った状態でも新規エントリーが発生することを確認すると、修正の効果が分かります。
実運用する前に確認しておきたいこと
RSIの逆張りは、レンジ相場では有効に機能しやすい一方、強いトレンドが出ている相場ではRSIが70以上・30未満に張り付いたまま反転せず、逆張りエントリーが繰り返し損切りに遭う(いわゆる「ダマシ」)ことがあります。実運用する前に、次の点を確認してください。
- トレンド相場かレンジ相場かを判断する指標(移動平均線の傾きなど)と組み合わせることを検討する
- ロット数(Lots)は口座残高に対して過大にならないよう調整する
- バックテストの結果は過去データに基づくものであり、将来の相場でも同じ成績になるとは限らない
まずはデモ口座、または少額のロットでのフォワードテスト(リアルタイムでの動作確認)を行ってから、本番運用を検討してください。
まとめ
RSIが70以上か30未満で逆張りトレードするEAの作り方を、実際に動くコードとあわせて解説しました。ポジションの有無をOrdersTotal()だけで判定すると他のEA・裁量ポジションと衝突すること、損切りを必ず設定することの2点を押さえておけば、実運用を検討できる形になります。
コメント