ネットで見つけたRSIを使ったEAのサンプルコードでは、`OrdersTotal()==0`のような書き方で「ポジションが無い時だけエントリーする」と説明されていることがあります。しかしOrdersTotal()は口座全体の保有注文数を数える関数なので、同じ口座で他のEAや裁量トレードのポジションを1つでも持っていると、このEA自体は条件を満たしているのに新規エントリーが発生しなくなる、という気づきにくい不具合が起きます。
この記事では、短期RSIと長期RSIを組み合わせて逆張りエントリーするEAを例に、パラメーターの設定からOnTick()関数の中身、そして見落としがちな「自分のポジションだけを判定する処理」と「損切り設定」まで、実際にMetaEditorでコンパイルしてMT4で動かせる状態のコードを解説します。
短期・長期の2種類のRSIを使ったEA
短期・長期の2種類のRSIを使ったEAを作成したいと思います。
- RSI短期3が10以下で長期RSI14が30以下でロングエントリー
- RSI短期3が90以上で長期RSI14が70以上でショートエントリー
という2つのRSIの条件が重なったらエントリーします。
メタエディタ(MetaEditor)を立ち上げる
MT4を起動し、ツールバーの黄色いボタン(またはツール→MetaQuotes Language Editor)からメタエディタ(MetaEditor)を立ち上げましょう。今回は名前を「double-RSI」で作成します。
メタエディタの「ファイル」→「新規作成」を選び、ウィザードで「Expert Advisor(テンプレートを使用)」を選択して名前を入力し、そのまま「次へ」を数回押して「完了」まで進めてください。OnInit()・OnDeinit()・OnTick()の3つの関数だけが書かれた空のひな形が開きます。
パラメーターを記述する
パラメーターを記述しましょう。今回は利確・損切り・ロット数・マジックナンバー・スリッページも含め、あとから値を変更しやすいようにinput変数として用意します。
input int Fast = 3;//短い期間のRSI input int Slow = 14;//長い期間のRSI input int TakeProfit = 5;//利確(pips) input int StopLoss = 10;//損切り(pips) input double Lots = 0.01;//ロット数 input int MagicNumber = 12345;//マジックナンバー input int Slippage = 3;//スリッページ
StopLossとSlippageは、後述する理由でこの記事から新しく追加したパラメーターです。
OnTick()関数を記述する
OnTick()関数を記述しましょう。
まず、それぞれの変数にiRSI関数の値を代入します。
double FastRSI = iRSI(NULL, 0, Fast, PRICE_CLOSE, 0); double SlowRSI = iRSI(NULL, 0, Slow, PRICE_CLOSE, 0);
長期RSIが30未満で、短期RSIが10未満の場合に
if(SlowRSI < 30 && FastRSI < 10)
ロングのポジションを持ちます。
OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,Ask-StopLoss*Point*10,Ask+TakeProfit*Point*10,"Order Long",MagicNumber,0,Lime);
ショートは逆で、長期RSIが70超、短期RSIが90超の場合に
if(SlowRSI > 70 && FastRSI > 90)
ショートポジションを持ちます。
OrderSend(Symbol(),OP_SELL,Lots,Bid,Slippage,Bid+StopLoss*Point*10,Bid-TakeProfit*Point*10,"Order Short",MagicNumber,0,Red);
これでエントリーのロジック自体はできましたが、このまま動かすと1つ問題が残っています。次のセクションで直します。
ポジションを重複して持たないようにする
元のコードは、ポジションの有無を`OrdersTotal() == 0`(口座全体の保有注文数)で判定していました。これだと、同じ口座で他のEAや裁量トレードのポジションを1つでも持っていた場合、このEA自体は条件を満たしていても、新規エントリーの判定そのものが動かなくなってしまいます。
このEA単体だけで口座を運用している場合は問題になりにくいですが、複数の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);
}
OnTick()の先頭に以下の1行を追加し、ポジションを持っている間は新規エントリーの判定自体をスキップします。
if(HasPosition()) return;//既にポジションがあれば新規エントリーしない
損切り(ストップロス)を設定する
元のOrderSend()は、6番目の引数(損切り価格)が0になっていました。0を指定すると損切りは設定されず、エントリーした方向と逆にRSIが動いても決済されないまま含み損が膨らみ続けます。
利確だけでなく損切りも必ず設定しましょう。パラメーターに追加したStopLossを使って、エントリー方向と逆側に損切りラインを計算します。
//買いの場合 Ask-StopLoss*Point*10 //売りの場合 Bid+StopLoss*Point*10
※このEAをそのまま動かして「エラーコード130(Invalid stops)」がログに出た場合、注文が失敗する原因のほとんどはStopLoss・TakeProfitの値がブローカーの最小ストップ距離より近いことです。エラー130が出た場合は、まずStopLoss・TakeProfitの値を大きくしてみてください。
ソースコード全体
ここまでの修正をすべて反映した、実際にMetaEditorでコンパイルしてそのまま動かせる状態のコードです。
//+------------------------------------------------------------------+
//| Double-RSI.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 Fast = 3;//短い期間のRSI
input int Slow = 14;//長い期間のRSI
input int TakeProfit = 5;//利確(pips)
input int StopLoss = 10;//損切り(pips)
input double Lots = 0.01;//ロット数
input int MagicNumber = 12345;//マジックナンバー
input int Slippage = 3;//スリッページ
//+------------------------------------------------------------------+
//| この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 FastRSI = iRSI(NULL, 0, Fast, PRICE_CLOSE, 0);//短い期間のRSI
double SlowRSI = iRSI(NULL, 0, Slow, PRICE_CLOSE, 0);//長い期間のRSI
int ticket;
if(SlowRSI < 30 && FastRSI < 10)//長期RSIが30より低く、短期RSIが10より低い場合
{
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(SlowRSI > 70 && FastRSI > 90)//長期RSIが70より高く、短期RSIが90より高い場合
{
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にdouble-RSIを選択、通貨ペアと期間を指定して、モデルを「全ティック(最も正確な値)」にしてスタートすると、過去データでの動作を確認できます。
実運用する前に確認しておきたいこと
このEAは2つのRSIが重なったタイミングだけで売買する、学習用にシンプルへ作った例です。実際の口座で稼働させる前に、次の点を確認してください。
- 短期RSI(Fast)と長期RSI(Slow)の閾値(10/90、30/70)は初期値の一例であり、通貨ペアや時間足によって最適な値は変わります
- レンジ相場ではRSIが極端な値を行き来しやすく、エントリーが連続して発生しやすい(いわゆる「ダマシ」)
- ロット数(Lots)は口座残高に対して過大にならないよう調整する
まずはデモ口座、または少額のロットでのフォワードテスト(リアルタイムでの動作確認)を行ってから、本番運用を検討してください。
まとめ
短期・長期の2種類のRSIを組み合わせて逆張りエントリーするEAの作り方を、実際に動くコードとあわせて解説しました。ポジションの重複防止と損切り設定まで含めて初めて、実運用を検討できる形になります。
コメント