ネットで見つけた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;//スリッページ
Copy

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);
  }
Copy

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());
     }
  }
//+------------------------------------------------------------------+
Copy

バックテストで動作を確認する

コードを保存したら、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の作り方を、実際に動くコードとあわせて解説しました。ポジションの重複防止と損切り設定まで含めて初めて、実運用を検討できる形になります。

関連記事