(EAコード無料公開)自分用FXMT4EAを作っていました

4月の中旬には「反省・・・OTZ」と言っていたのにもかかわらず、再度ブログの更新をサボってしまいすみませんでした(ノ_く。)
4月後半からGW連休にかけてMT4EA制作に夢中になってしまいました・・・OTZ

先程エラー無く動作したEAが完成して少し感動してしまいましたが、実はまだ思っていた通りのEAというわけではありません。
素人なので失敗ばかりしていて時間が掛かっていました。
かなりの数の失敗作を放棄して結局シンプルなものに戻ってしまったという感じです。
また時間が取れたら改訂版のEAを制作してみたいです。

ここまで話しておきながらMT4とは?EAとは?なんぞや?という方へ説明をしますと、MT4というのはメタトレーダーと呼ばれるFXの取引ツールのことで、恐らく未だにFX取引ツールとしてのシェアはNo.1なのではないかと思います。
そしてEAというのはMT4上で稼働する自動売買プログラムのことです。
今回のEAはOandaJapanのMT4の設定で作っているので、細かい設定が異なる場合にはご自身での調整が必要です。

他人の作るEAを信用せずにご自身で納得できるEAを作る事をお勧めしますが、自分用の記録あるいは改良の進捗状況の参考程度にコードをこの記事の下に貼ります。
まだ練習作一号なので内容を何一つ保証できません。自己責任でご利用ください。
特にLive口座での稼働はお勧めできません。
逆にこう書くべきみたいなのがあれば教えて貰えると嬉しいです。

MT4の画面ですと「自動売買」ボタンの左3つ隣に「メタクウォーツ言語エディタ」ボタンがあり、それを押してMetaEditorを開いてから「新規作成」ボタンを押してコードをコピペしてから任意の名前を付けて保存して「コンパイル」ボタンを押せば、MT4再起動後「ナビゲーター」から個別のチャートへEAを貼る事でお試しのEA稼働ができるはずです。

「FX勝率100%の方法」「FX全戦全勝の方法計算例 」の記事でも説明しましたように、ニャン吉は損切りの必要のない資金管理を重視しています。
今回制作したEAはこの考えを実行することを意図していて、設定次第では損切りの必要がありません
逆にいうと設定次第では全戦全勝どころかひたすら負ける可能性もあるので、今回のEAを真似する場合には設定内容には充分に注意してください。
また、大まかに言うと100万円で0.1ロットを1~2ポジション(1通貨ペア1ポジション)の割合で利用するように作りました。相変わらずの安全優先です。

本当は全戦全勝、勝率100%と言いたいところですが、今回のEAはほぼ建値決済の可能性もあり約定のスリップ次第では理論上個々の取引でスリップ分負ける可能性があります。
またスワップ次第では損益がマイナスになってしまうこともあるので注意が必要です。
マイナススワップの方向でのエントリーには上限下限の設定を用いて大きめに制限を掛けるようにしてください。

今回のEAは上限下限の設定内で日足200SMAの上でRSIが70に達すれば売り、SMA下でRSIが30になれば買いというシンプルなものです。
一応RSIの折り返しでエントリーするように条件を追加してありますが、細かい上下にも反応してしまうので、結局あまりエントリーポイントに差はありませんでした。
決済はトレールストップのみの100pips幅設定にしてあります。
バックテストでは仕様上、含み損を期末に強制決済されてしまうので、バックテストを利用する場合には最終取引を無視してください
実際の取引では期間末に強制決済なんて行われず、含み損に耐える事を前提としたEAです。

バックテストで遊んだ後はMT4の「データフォルダーを開く」から「tester」の中にある「history」と「logs」にゴミファイルが貯まるので捨てた方がいいです。放置するとドライブディスク容量を占拠してしまいます。
間違っても「tester」の中ではない方の「history」と「logs」は触ってはいけません!
とんでもないことになりますよ(ノ_く。)

今回のEAは一旦USDJPY日足での使用を前提として設定をしてありますが、GBPJPYのように動きが激しい通貨ペアなら「買い上限」「売り下限」を調整して安全圏を確保することをお勧めします。

例えば買い上限109.0を150.0にしたり、売り下限111.0を215.0にするとGBPJPYの実効レバレッジ2倍程度でもなんとか耐えられるようになります。

今回のEAでは安全性を重視してレバレッジ2倍くらいになるように、ポジション数上限下限の設定でレバレッジ調整をすることを強くお勧めします。
レバレッジやポジション計算には「FX勝率100%の方法」で紹介した計算方法の他、証拠金・損益シミュレーション | OANDA FX計算ツール (hirose-fx.co.jp)を利用してみてください。

過去の記事から何度も繰り返しとなってしまいますが、まずはロスカットラインを過去30年の値幅の外に置いて安全圏を確保することを重視しましょう。
本人が納得できる長期的に見ても到達することのない価格にロスカットラインを設定することによって損切りそのものが不要となります。損切り貧乏にならなくて済むわけです。
このEAには損切りの機能がありません。
ロスカットラインは自己責任で計算して、ご自身の納得できる場所に置いてください。
通貨ペアによって異なりますがレバレッジ2倍のロットとポジションなら、ロスカットラインから4000pips以内に売り買いの上限下限を設定しておけば充分安全だと思います。

1通貨ペアにつき1ポジションの設定になっているので、資金に余裕があればロット数を増やすよりも、複数の通貨ペアにEAを設定するとリスク分散にもなり安全性が高まります。
ポジション数や設定についての細かい話はまた後日にしたいと思います。
特にトレーリング設定で改良の必要性はあるものの、とりあえず欲しかった内容のEAが完成してホッとしました^^

//+------------------------------------------------------------------+
//|                                                          ニャン吉EA |
//|                       商用利用及び再配布を禁じます,c2021.5.5,ニャン吉ちゃんねる|
//|                                          https://ニャン吉ちゃんねる.com |
//|                                      (OandaMT4を前提とした設定内容です) |
//+------------------------------------------------------------------+
#property copyright   "商用利用及び再配布を禁じます,c2021.5.5,ニャン吉ちゃんねる"
#property link        "https://ニャン吉ちゃんねる.com"
#property description "(OandaMT4を前提とした設定内容です)"
#property strict

input int    Magic =11;//通貨ペア毎に別ナンバー割り振る(0は避ける)
input double Lot =0.1;//ロット(ロット数よりも通貨ペアを追加してポジション数増を推奨)
input double Kagen =120;//売り下限(デフォルトはUSDJPYでの一例)
input double Jougen =108;//買い上限(デフォルトはUSDJPYでの一例)

input int MAPeriod =200;//SMA(日足チャート推奨・200を推奨)
input int TrailingStart =1000;//トレール開始幅(1000points=100pips)
input int TrailingStop  =300;//トレールストップ幅(500points=50pips)
input int MaxSpread  =30;//スプレッドによるエントリー制限(30points=3pips)
input int MaxSlippage =10;//スリッページによるエントリー制限(10points=1pip)

int      RSIPeriod  =9;
double   RSIUpper   =70;
double   RSILower   =30;
double   TakeProfit =0;

   //エントリーカウント
   int CurrentOrder()
    {
   int cnt=0; 
   for(int i=0;i<OrdersTotal();i++) {   
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderSymbol()!=Symbol() || OrderMagicNumber()!=Magic) continue;     
      if(OrderType()==OP_BUY) {
         cnt++;
      }
      if(OrderType()==OP_SELL){
         cnt++;
      }   
    }
    return(cnt);
    }   

void OnTick(void)
  {
   double MACurrent,RSICurrent;
   int    cnt,ticket,total;

   if(Bars<100)
     {
      Print("bars less than 100");
      return;
     }

   MACurrent=iMA(NULL,0,MAPeriod,0,MODE_SMA,PRICE_CLOSE,0);
   RSICurrent=iRSI(NULL,0,RSIPeriod,PRICE_CLOSE,0);
   total=OrdersTotal();   

   if(CurrentOrder()<1)
     {   
     
      if(AccountFreeMargin()<(1000*Lot))
        {
         Print("We have no money. Free Margin = ",AccountFreeMargin());
         return;
        }


    // 買エントリー処理
    if(Ask<Jougen && Ask<MACurrent && RSICurrent<RSILower && MarketInfo(Symbol(),MODE_SPREAD)<MaxSpread )
        {
         ticket=OrderSend(Symbol(),OP_BUY,Lot,Ask,MaxSlippage,0,0,NULL,Magic,0,Green);
         if(ticket>0)
           {
            if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
               Print("BUY order opened : ",OrderOpenPrice());
           }
         else
            Print("Error opening BUY order : ",GetLastError());
         return;
        }

    // 売エントリー処理
    if(Bid>Kagen && Bid>MACurrent && RSICurrent>RSIUpper && MarketInfo(Symbol(),MODE_SPREAD)<MaxSpread )
        {
         ticket=OrderSend(Symbol(),OP_SELL,Lot,Bid,MaxSlippage,0,0,NULL,Magic,0,Red);
         if(ticket>0)
           {
            if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
               Print("SELL order opened : ",OrderOpenPrice());
           }
         else
            Print("Error opening SELL order : ",GetLastError());
        }
        
      return;
     }

   // トレールストップ処理
   for(cnt=0;cnt<total;cnt++)
     {
      if(!OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES))
         continue;
      if(OrderType()<=OP_SELL &&   
         OrderSymbol()==Symbol())  
        {

         if(OrderType()==OP_BUY)
           {
            if(TrailingStop>0)
              {
               if(Bid-OrderOpenPrice()>Point*TrailingStart)
                 {
                  if(OrderStopLoss()<Bid-Point*TrailingStop)
                    {
                     if(!OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green))
                        Print("OrderModify error ",GetLastError());
                     return;
                    }
                 }
              }
           }
         else 
           {
            if(TrailingStop>0)
              {
               if((OrderOpenPrice()-Ask)>(Point*TrailingStart))
                 {
                  if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
                    {
                     if(!OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red))
                        Print("OrderModify error ",GetLastError());
                     return;
                    }
                 }
              }
           }
        }
     }
  }

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です