自作関数を作ってソースコードをわかりやすくしよう

こんにちは~。

MQLをマスターしたくて、在宅勤務になってから外に出なくて暑くないのでビールのうまさを忘れかけているりょうです。

今回は、前回製作したiCustomを使ったEAを少し改造してみる試みです。

TOC

MQL4で定義された関数と自作の関数


早速なのですが、今回改造をしたEAがこちらです↓。

//+------------------------------------------------------------------+
//|                                                   heikenTEST.mq4 |
//|                        Copyright 2022, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

input uint RSIPeriod = 14;                             //RSIを計算する期間
input uint RSIUpperLine = 70;                          //RSIの上ライン
input uint RSILowerLine = 30;                          //RSIの下ライン

datetime NewBar;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
//---

//---
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
//---

}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick() {

//1本前の平均足の値を取得
   double HeiOpen1 =  iCustom(Symbol(), PERIOD_CURRENT, "Heiken Ashi", 2, 1);
   double HeiClose1 =  iCustom(Symbol(), PERIOD_CURRENT, "Heiken Ashi", 3, 1);
//2本前の平均足の値を取得
   double HeiOpen2 =  iCustom(Symbol(), PERIOD_CURRENT, "Heiken Ashi", 2, 2);
   double HeiClose2 =  iCustom(Symbol(), PERIOD_CURRENT, "Heiken Ashi", 3, 2);
//1本前のRSIの値を取得する
   double RSI1 = iRSI( NULL, 0, RSIPeriod, PRICE_CLOSE, 1 );

//以下、新しいローソク足になった時の処理
   if( NewBar != Time[0]) {
      NewBar = Time[0];

//陽線から陰線に切り替わったらロング決済、陰線から陽線に切り替わったらショート決済
      for( int i = OrdersTotal() - 1; i >= 0; i--) {
         if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == true) {
            if((OrderType() == OP_BUY && HeiOpen2 < HeiClose2 && HeiOpen1 > HeiClose1) ||
                  ( OrderType() == OP_SELL && HeiOpen2 > HeiClose2 && HeiOpen1 < HeiClose1)) {
               int result = OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), 0);
               if(result < 0) {
                  Print("注文に失敗しました");
               } else {
                  bool orderSelectResult = OrderSelect(result, SELECT_BY_TICKET);
                  Print("注文に成功しました。決済価格は " + (string)OrderClosePrice() + " です。");
               }
            }
         }
      }

//エントリー
//RSIが下ライン以下で平均足が陰線から陽線に切り替わったらロングエントリー
      if( (HeiOpen2 > HeiClose2 && HeiOpen1 < HeiClose1) &&
            RSIUnderLowerThreshold(RSI1)) {
         int result = OrderSend( Symbol(), OP_BUY, 0.5, Ask, 1, 0, 0, NULL );
         if(result < 0) {
            Print("注文に失敗しました");
         } else {
            bool orderSelectResult = OrderSelect(result, SELECT_BY_TICKET);
            Print("注文に成功しました。エントリー価格は " + (string)OrderOpenPrice() + " です。");
         }
      }
//RSIが上ライン以上で平均足が陽線から陰線に切り替わったらショートエントリー
      if( (HeiOpen2 < HeiClose2 && HeiOpen1 > HeiClose1) &&
            RSIOverUpperThreshold(RSI1)) {
         int result = OrderSend( Symbol(), OP_SELL, 0.5, Bid, 1, 0, 0, NULL );
         if(result < 0) {
            Print("注文に失敗しました");
         } else {
            bool orderSelectResult = OrderSelect(result, SELECT_BY_TICKET);
            Print("注文に成功しました。エントリー価格は " + (string)OrderOpenPrice() + " です。");
         }
      }
   }
}

//+------------------------------------------------------------------+
//RSIが上ライン以上になるとtrue
bool RSIOverUpperThreshold(double rsi) {
   if( RSIUpperLine <= rsi )return true;
   else return false;
}
//+------------------------------------------------------------------+
//RSIが下ライン以下になるとtrue
bool RSIUnderLowerThreshold(double rsi) {
   if( RSILowerLine >= rsi )return true;
   else return false;
}
//+------------------------------------------------------------------+



前回、iCustomを使ってみようという事で平均足を使ったEAを作成したのですが、ロジックが平均足1つだけだったのでもう1つロジックをくっつけて改造しました。

改造した部分がこちらです↓。

input uint RSIPeriod = 14;                             //RSIを計算する期間
input uint RSIUpperLine = 70;                          //RSIの上ライン
input uint RSILowerLine = 30;                          //RSIの下ライン

//1本前のRSIの値を取得する
   double RSI1 = iRSI( NULL, 0, RSIPeriod, PRICE_CLOSE, 1 );


//RSIが下ライン以下で平均足が陰線から陽線に切り替わったらロングエントリー
      if( (HeiOpen2 > HeiClose2 && HeiOpen1 < HeiClose1) &&
            RSIUnderLowerThreshold(RSI1)) {
・
・
・
・
・



//RSIが上ライン以上で平均足が陽線から陰線に切り替わったらショートエントリー
      if( (HeiOpen2 < HeiClose2 && HeiOpen1 > HeiClose1) &&
            RSIOverUpperThreshold(RSI1)) {
・
・
・
・
・




//+------------------------------------------------------------------+
//RSIが上ライン以上になるとtrue
bool RSIOverUpperThreshold(double rsi) {
   if( RSIUpperLine <= rsi )return true;
   else return false;
}
//+------------------------------------------------------------------+
//RSIが下ライン以下になるとtrue
bool RSIUnderLowerThreshold(double rsi) {
   if( RSILowerLine >= rsi )return true;
   else return false;
}
//+------------------------------------------------------------------+


にゃんぽこ

RSIが足されておる

りょう

足してみました


これで、RSIが下ライン以下で平均足が陰線から陽線に変わったときにロングエントリー、RSIが上ライン以上で平均足が陽線から陰線に変わったときにショートエントリーというロジックになりました。

りょう

やはりせっかくプログラムを組むのだから2つ以上のロジックでなくてはやりがいが無い


今回改造したソースコードなのですが、2種類の関数を使用しています。

1つはMQL4にデフォルトで定義されているiRSI()関数。

もう1つは自分で作成したRSIOverUpperThreshold()関数とRSIUnderLowerThreshold()関数です。

ムゥ

関数は自分でも作れるんだにゃあ~

りょう

はい 作ってみました


関数というと最初にイメージするのは

  • iMA ・・・ 移動平均線の値を取得する関数
  • iRSI ・・・ RSIの値を取得する関数
  • iStochastic ・・・ ストキャスティクスの値を取得する関数

のように、MQL4にデフォルトで定義されている関数だと思います。

これらを使用することでMAやRSIの値を1行のコードで取得してくれるので重宝しますが、プログラミングでできることは多岐にわたり、上記のようなメジャーなテクニカルの数値以外にも一発で値を取得したい場面というのは日常茶飯事です。

りょう

日常茶飯事とは、日々のありふれたこと

ムゥ

その解説いらんにゃ

そこで関数を自作で定義することで、取得したい値を一発で行ってくれるようにできます。

処理を関数化することで

  1. 実際の処理の部分のソースコードが簡素化されて見やすくなる
  2. 関数化しておけば別のプログラムにコピーしやすくなる

など、仕事がしやすくなります。

りょう

コードがすっきりしてコピペしやすいのはいいねぇ~

自作関数の引数について

今回の関数の

//+------------------------------------------------------------------+
//RSIが上ライン以上になるとtrue
bool RSIOverUpperThreshold(double rsi) {
   if( RSIUpperLine <= rsi )return true;
   else return false;
}
//+------------------------------------------------------------------+
//RSIが下ライン以下になるとtrue
bool RSIUnderLowerThreshold(double rsi) {
   if( RSILowerLine >= rsi )return true;
   else return false;
}
//+------------------------------------------------------------------+


ですが、どちらも(double rsi)という引数を使用しています。

これはMQL4のデフォルト関数のiRSI()を例に挙げると()の中の



↑これらにあたります。

iRSI()は(通貨ペア、時間軸、期間、適用価格、シフト)の順番にキチンと引数を入れないといけませんでした。

にゃんぽこ

順番は守らんとあかんよ


自作の関数も同じで、今回は引数が1つだけでしたがきちんと引数の順番を守らなくてはいけません。

なので、例えば

//RSIが上ライン以上になるとtrue
bool RSIOverUpperThreshold(double rsi) {
   if( RSIUpperLine <= rsi )return true;
   else return false;
}


↑この関数をこのように↓

//RSIが上ライン以上になるとtrue
bool RSIOverUpperThreshold(double rsi, double shortentryline) {
   if( shortentryline <= rsi )return true;
   else return false;
}


(double rsi, double shortentryline)と2つの引数を用意したら、ちゃんと順番通りに引数を入れなければなりません。

double rsi』はRSIの数値、『 double shortentryline 』 はRSIの上ラインの数値を入れなければいけないため、今回の場合はこのようになります↓。

//RSIが上ライン以上で平均足が陽線から陰線に切り替わったらショートエントリー
      if( (HeiOpen2 < HeiClose2 && HeiOpen1 > HeiClose1) &&
            RSIOverUpperThreshold(RSI1,RSIUpperLine)) {
・
・
・
・
・




//+------------------------------------------------------------------+
//RSIが上ライン以上になるとtrue
bool RSIOverUpperThreshold(double rsi, double shortentryline) {
   if( shortentryline <= rsi )return true;
   else return false;
}



RSIOverUpperThreshold(RSI1,RSIUpperLine)と記載し、(RSIの数値、RSIの上ラインの数値)と順番通りに入れています。

RSI1はRSI関数で取得した値、RSIUpperLineはパラメータで自分で設定した値です。

にゃんぽこ

順番は守らんとあかんよ

りょう

何回言うねん


ちなみに、このような関数の書き方もできます↓。

//RSIが上ライン以上になるとtrue
bool RSIOverUpperThreshold() {
//1本前のRSIの値を取得する
   double RSI1 = iRSI( NULL, 0, RSIPeriod, PRICE_CLOSE, 1 );

   if( RSIUpperLine <= RSI1 )return true;
   else return false;
}


関数の中にiRSI()関数を持ってきたとしたら、引数は不要になりますね。

りょう

なるほどぉ


その際はこんな感じになります↓。

input uint RSIPeriod = 14;                             //RSIを計算する期間
input uint RSIUpperLine = 70;                          //RSIの上ライン
input uint RSILowerLine = 30;                          //RSIの下ライン


//RSIが下ライン以下で平均足が陰線から陽線に切り替わったらロングエントリー
      if( (HeiOpen2 > HeiClose2 && HeiOpen1 < HeiClose1) &&
            RSIUnderLowerThreshold()) {
・
・
・
・
・



//RSIが上ライン以上で平均足が陽線から陰線に切り替わったらショートエントリー
      if( (HeiOpen2 < HeiClose2 && HeiOpen1 > HeiClose1) &&
            RSIOverUpperThreshold()) {
・
・
・
・
・




//+------------------------------------------------------------------+
//RSIが上ライン以上になるとtrue
bool RSIOverUpperThreshold() {
//1本前のRSIの値を取得する
   double RSI1 = iRSI( NULL, 0, RSIPeriod, PRICE_CLOSE, 1 );
   if( RSIUpperLine <= RSI1 )return true;
   else return false;
}
//+------------------------------------------------------------------+
//RSIが下ライン以下になるとtrue
bool RSIUnderLowerThreshold() {
//1本前のRSIの値を取得する
   double RSI1 = iRSI( NULL, 0, RSIPeriod, PRICE_CLOSE, 1 );
   if( RSILowerLine >= RSI1 )return true;
   else return false;
}
//+------------------------------------------------------------------+


ムゥ

コードの書き方は十人十色にゃ

にゃんぽこ

いやぁほんっとに、MQLって奥が深いですね

それではまた

りょう

えっ 何その締め方

TOC
閉じる