MetaTrader 4 プログラム中級編

オリジナル関数の作り方




 今回は、オリジナル関数の作り方です。


 そろそろ内容が少し難しくなって来ましたので、今回から中級編にします。


 サンプルプログラムはこちらです。


 http://jidoubaibai.com/Samples/Sample%20New%20Kannsuu.mq4


 サンプルプログラムの使い方は、こちらで説明しています。 


 http://jidoubaibai.com/burogu11.html



 では、MetaEditorを起動して下さい。


 NameはNewKannsuuにして置いて下さい。


 では、まとめてコードを書きますので、同じようにコードを半角英数で書いていってください。





int start()
{
   //変数の宣言
   int cnt, CurrentPosition;
   int Ticket;   


   // オーダーチェック(ポジションなどのデータ)
   CurrentPosition=-1;
   for(cnt=0;cnt < OrdersTotal();cnt++){
      OrderSelect(cnt,SELECT_BY_POS);
      if(OrderSymbol() == Symbol()) CurrentPosition=cnt;
   }




   // ポジションチェック ポジション無し
   if(CurrentPosition == -1)
   {
      //もしメインがシグナルを下から上にクロスしたら
      if( CrossMACD(12,26,9) == 1 )
      {
         //買いポジションを取る
         Ticket = OrderSend(Symbol(), OP_BUY, 1, Ask, 3, Ask-(200*Point), Ask+(200*Point), "Buy", 0, 0, Red);
      }

      //もしメインがシグナルを上から下にクロスしたら
      if( CrossMACD(12,26,9) == 2)
      {
         //売りポジションを取る
         Ticket = OrderSend(Symbol(), OP_SELL, 1, Bid, 3,  Bid+(200*Point), Bid-(200*Point), "Sell", 0, 0, Blue);
      }



   }
   // ポジション有り
   else
   {

      //ポジションの選択
      OrderSelect(CurrentPosition,SELECT_BY_POS);

      //通貨ペアの確認
      if(Symbol() == OrderSymbol())
      {
         //もし買いポジションだったら
         if(OrderType()==OP_BUY)
         {
            //もしメインがシグナルを上から下にクロスしたら
            if( CrossMACD(12,26,9) == 2)
            {
               //手仕舞い
               OrderClose(OrderTicket(),OrderLots(),Bid,3,Green);

               //ドテンで売りポジションを取る
               Ticket = OrderSend(Symbol(), OP_SELL, 1, Bid, 3,  Bid+(200*Point), Bid-(200*Point), "Sell", 0, 0, Blue);
            }

         }
         //もし売りポジションだったら
         else if(OrderType()==OP_SELL)
         {
            //もしメインがシグナルを下から上にクロスしたら
            if( CrossMACD(12,26,9) == 1)
            {
               //手仕舞い
               OrderClose(OrderTicket(),OrderLots(),Ask,3,Green);

               //ドテンで買いポジションを取る
               Ticket = OrderSend(Symbol(), OP_BUY, 1, Ask, 3,  Ask-(200*Point), Ask+(200*Point), "Buy", 0, 0, Red);
            }
         }
      }


   }
   return(0);
}



/*------------------------------------------------------
関数名   CrossMACD
内容     MACDのゴールデンクロスとデッドクロスを判断する関数

引数     int fast    短期EMA
        int slow    長期EMA
        int signal  シグナル

戻り値   0:何も出来ていない 1:ゴールデンクロス
         2:デッドクロス
-------------------------------------------------------*/
int CrossMACD(int fast,int slow,int signal)
{
   double kakoa,gennzaia;
   double kakob,gennzaib;


   //一つ前のMACDのメイン
   kakoa = iMACD(NULL,0,fast,slow,signal,PRICE_CLOSE,MODE_MAIN,1);
   //一つ前のMACDのシグナル
   kakob = iMACD(NULL,0,fast,slow,signal,PRICE_CLOSE,MODE_SIGNAL,1);

   //現在のMACDのメイン
   gennzaia = iMACD(NULL,0,fast,slow,signal,PRICE_CLOSE,MODE_MAIN,0);
   //現在のMACDのシグナル
   gennzaib = iMACD(NULL,0,fast,slow,signal,PRICE_CLOSE,MODE_SIGNAL,0);


   //もしメインがシグナルを下から上にクロスしたら
   if( kakoa < kakob && gennzaia >= gennzaib)
   {
      return(1);
   }

   //もしメインがシグナルを上から下にクロスしたら
   if( kakoa > kakob && gennzaia <= gennzaib)
   {
      return(2);
   }


   return(0);
}




 書けましたか?


 今回は、関数というものを新しく作り、その中でMACDのゴールデンクロスとデッドクロスを見分ける処理をさせています。


 関数というものは、呼び出すたびに関数の中の処理をまとめて行ってくれるものと覚えて置いてください。


 関数を作ってまとめることで、プログラムの中身が分かりやすくコンパクトになります。


 また、一度作ってしまえば、他のプログラムにコピーすることによって、作業が楽になります。



 では、内容の説明をして行きますね。


 前回と違うのは、 if( CrossMACD(12,26,9) == 1 ) このコードと、start関数より下の新しく作った関数ですね。


 まず、関数の作り方を説明して行きます。


 日本語に訳すと次のようになります。


型 関数名(引数)
{
  内容

  return(戻り値)
}


 見慣れない言葉があると思いますので、もう少しバラして説明して行きますね。



 まず、型 関数名()です。


 これは、変数の宣言とほとんど同じです。


 int型などの型を宣言して、次に好きな関数名を入れてください。


 型は、後で説明する戻り値の型になりますので、それを考慮して下さい。




 次に、引数です。


 int CrossMACD(int fast,int slow,int signal) の()の中にあるものが引数です。


 これは、関数を使うときにパラメーターなどを入力出来るようにするためのものです。


 今回はMACDを計算する時のパラメーターを入力出来るようにしています。


 引数は、変数と似たような使い方が出来ます。


 関数を呼び出すときに、CrossMACD(12,26,9)と入力していれば、fast,slow,signalにそれぞれ12,26,9が入っています。


 後は、変数と同じように下のコードのように使えます。


kakoa = iMACD(NULL,0,fast,slow,signal,PRICE_CLOSE,MODE_MAIN,1);



 引数の宣言の仕方も変数の宣言の仕方とほとんど同じです。


 ()の中に、型と好きな引数名を書くだけです。


 複数ある場合は、,(カンマ)を間に入れてください。


 また、引数が不要の場合は、()の中に何も書かなくても問題ありません。




 最後に、戻り値です。


 これは、関数から戻ってくる値です。


 return(戻り値); この()の中に戻り値を書けば、関数から値を渡すことが出来ます。


 計算結果の答えなどを返すのに使います。


 例を出すと、CrossMACD(12,26,9);と入力して、関数の最後がreturn(1);だった場合は、CrossMACD(12,26,9);の中には1が入っています。


 ですので、if(CrossMACD(12,26,9) == 1){}というような使い方が出来ます。


 また、このreturn();はこれが使われた時点でその関数は終了するので、次のようにも使えます。


if(条件1)
{
  return(1);
}
else if(条件 2)
{
  return(2);
}

return(0);



 このように、計算結果が条件に当てはまったら、その条件によって戻り値を変えて、どの条件にも当てはまらなかったら0を返しています。


 最後に注意点ですが、return();が無かったらその関数が終わりませんので、最後に絶対に一つは書いて置いてください。




 関数の作り方の説明はこれで終わりです。


 次に作った関数の使い方です。


 CrossMACD(12,26,9);


 先程作った関数名(引数に入力する値)で使用出来ます。


 また、戻り値が中にありますので、if(CrossMACD(12,26,9)==1){}という使い方も可能です。




 これで今回のプログラムの説明は終了です。


 今回は関数を作っただけで、結果自体は前回と全く同じです。


 では、コンパイルをするためにcompileのボタンを押してください。


 エラーが出てきた場合は、半角になっているか、;を付け忘れていないか、{}を付け忘れていないか、{}の数は合っているかを確認して下さい。


 どうしてもエラーが分からない場合は、サンプルプログラムを参照して下さい。


 エラーが出なかったら、MetaTrader 4バックテストNewKannsuuを選んで、スタートして下さい。


 終わったら、結果、Graph、レポートを見てください。


---------------------------------------------------
 popperさんに指摘されて気がついたのですが、リアル売買ではこのプログラムコードで正しいのですが、バックテストのOpen prices onlyの時だけ、このコードが間違いになります。(他の二つはこれで正しいです)


 start関数を呼び出すのがOpen prices onlyだけ始値の一度だけというのが原因なのですが、Open prices onlyだけは、変数の内容を下のようにしなければなりません。


   //一つ前のMACDのメイン
   kakoa = iMACD(NULL,0,fast,slow,signal,PRICE_CLOSE,MODE_MAIN,2);
   //一つ前のMACDのシグナル
   kakob = iMACD(NULL,0,fast,slow,signal,PRICE_CLOSE,MODE_SIGNAL,2);

   //現在のMACDのメイン
   gennzaia = iMACD(NULL,0,fast,slow,signal,PRICE_CLOSE,MODE_MAIN,1);
   //現在のMACDのシグナル
   gennzaib = iMACD(NULL,0,fast,slow,signal,PRICE_CLOSE,MODE_SIGNAL,1);


 最後のシフトを1つずつ増やさなければなりません。


 ややこしいと思いますが、宜しくお願いします。

---------------------------------------------------
---------------------追記--------------------------

 この不具合について分からないとメールを頂きましたので、もう少し詳しく説明してみます。


 この不具合は、売買タイミングの条件が細かいシステムをOpen priceのモードでバックテストするとおきる不具合のようです。


 ゴールデンクロス、デッドクロスなどの売買条件を使ったシステムが当てはまることが多いです。


 かなりややこしいのであまり簡単に説明は出来ないのですが、なんとか例えを出しながら説明してみます。



 前回のMACDのシステムの売買ルールは、一時間前のMACDのメインがシグナルより低いのが条件で、現在のMACDのメインがシグナルより高いのが条件なのですが、Open priceにすると、条件が成立した時間によっては例え条件が成立していても売買されなくなります。


 何故かと言うと、start関数が呼び出される頻度に問題があります。


 例を出すと、1時に条件が不成立で、1時半に条件が成立したとします。


 1時の段階では、一時間前の足のMACDと現在の足のMACD両方ともメインの方が低いです。


 1時半の段階では、一時間前の足のMACDはメインの方が低くて、現在の足のMACDはクロスしてメインの方が高くなり、条件成立ですが、start関数が呼び出されないため、まだ売買処理はされません。


 2時になって足が変わってからstart関数が呼び出されましたが、その時点では一時間前の足のMACDと現在の足のMACDの両方ともメインの方が高くなっていて、条件不成立になります。



 ややこしいと思いますので、もう少し説明を付け加えると、start関数が呼び出された時点での現在の足はほとんど出来ていないので、start関数が呼び出された現在の足と一時間後から見た一時間前の足が異なるものになるのが原因です。


 売買ルールから一時間前にメインがシグナルより低いという条件を無くし、「メインがシグナルを上回ったら」だけにすれば問題がなくなるのですが、それだとストップロスとリミットをつけ、決済された場合にまだメインがシグナルを上回っていたら、決済したその場で買いポジションを持たされます。


 適当に何か条件をつけてこの状態を回避する方法もありますので、色々と試してみるのも経験になって良いと思いますよ。



 最後に、リアル売買や他の二つのバックテストのモードでは、この不具合は起きません。


 リアル売買とバックテストの他の二つのモードは頻繁にstart関数が呼び出されますので、クロスした瞬間に売買されるからです。


 インジケーターのクロスする系のシステムを作る場合は忘れずに覚えておいたほうが良いですね。


---------------------------------------------------






iMACD レポート ドル円一時間足





iMACD グラフ ドル円一時間足





 今回はこれで終了です。


 関数は一度作れば、次からのプログラムが楽になりますので、頑張って作ってみてください。

 次回の内容は、複数のシステムによる自動売買の仕方です。

---------------------------------------------------

 コードを見易くするために全角で書いている場合があります。
 実際にプログラムにコードを書くときは、コピー&ペーストせずに半角で書いて行って下さい。

<< 二次元配列について | TOP | 複数のシステムによる自動売買の仕方 >>

トップページ プロフィール ブログ リンク オーダーシステム 利用規約 問い合わせ