goo blog サービス終了のお知らせ 

海外FX口座でFXMT4自動売買に挑戦!

XMTrading,TitanFM,iFOREXなどの海外FX口座でMT4を使ってFX自動売買に挑戦

カーブフィッティングの恐ろしさ

2018-06-02 00:31:35 | MT4(メタトレーダー4)
前回は、移動平均線とATRを使ったEAを作り、
2017.1.1-2018.1.1の期間ではそこそこよかったのですが、
MA+ATR

同じEAで同じ条件、ただし2016.1.1-2018.1.1と期間を広げると2016から1年間ほどは見事に右肩下がり。
ダウンロード
これがカーブフィッティングって奴なんでしょうかね…
長期間でバックテストすると時間かかりますし、1年ぐらいでバックテストした後にもっと長期で問題ないか試すべきですね。

移動平均線のクロスとATRを使ったEA

2018-05-31 18:46:02 | MT4(メタトレーダー4)
前回お勉強したATRを移動平均線クロスに取り込みました。
ATRが0.1以上のボラティリティがあるときにエントリーして、
ATRの2.5倍値動きで損切・利確です。
OrderSendで注文時に損切・利確も決めてエントリーしてるので前の

Moving Average.mq4を移動平均線のゴールドクロス・デッドクロスに改造
http://trading-fx.blog.jp/archives/9191662.html

から決済の"Check for close order conditions”をバッサリカット。
あと、デフォルトで移動平均線のシフトが6になってたのを0に変更。
//+------------------------------------------------------------------+
//|                                                       MA+ATR.mq4 |
//|                 Copyright 2018,海外FX口座でFXMT4自動売買に挑戦! |
//|                                       http://trading-fx.blog.jp/ |
//+------------------------------------------------------------------+
#property copyright   "Copyright 2018,海外FX口座でFXMT4自動売買に挑戦!"
#property link        "http://trading-fx.blog.jp/"
#property description "MA+ATR"
#define MAGICMA  20180531
//--- Inputs
input double Lots          =0.1;
input double MaximumRisk   =0.02;
input double DecreaseFactor=3;
input int    MovingPeriodS =7;
input int    MovingPeriodL =22;
input int    MovingShift   =0;
input int    ATRperiod     =8;
input double ATRLevel      =0.1;
input double stoploss      =2.5;
input double takeprofit    =2.5;
//+------------------------------------------------------------------+
//| Calculate open positions                                         |
//+------------------------------------------------------------------+
int CalculateCurrentOrders(string symbol)
  {
   int buys=0,sells=0;
//---
   for(int i=0;i<OrdersTotal();i++)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGICMA)
        {
         if(OrderType()==OP_BUY)  buys++;
         if(OrderType()==OP_SELL) sells++;
        }
     }
//--- return orders volume
   if(buys>0) return(buys);
   else       return(-sells);
  }
//+------------------------------------------------------------------+
//| Calculate optimal lot size                                       |
//+------------------------------------------------------------------+
double LotsOptimized()
  {
   double lot=Lots;
   int    orders=HistoryTotal();     // history orders total
   int    losses=0;                  // number of losses orders without a break
//--- select lot size
   lot=NormalizeDouble(AccountFreeMargin()*MaximumRisk/1000.0,1);
//--- calcuulate number of losses orders without a break
   if(DecreaseFactor>0)
     {
      for(int i=orders-1;i>=0;i--)
        {
         if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false)
           {
            Print("Error in history!");
            break;
           }
         if(OrderSymbol()!=Symbol() || OrderType()>OP_SELL)
            continue;
         //---
         if(OrderProfit()>0) break;
         if(OrderProfit()<0) losses++;
        }
      if(losses>1)
         lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);
     }
//--- return lot size
   if(lot<0.1) lot=0.1;
   return(lot);
  }
//+------------------------------------------------------------------+
//| Check for open order conditions                                  |
//+------------------------------------------------------------------+
void CheckForOpen()
  {
   double maS0;
   double maS1;
   double maL0;
   double maL1;
   double ATR;
   int    res;
//--- go trading only for first tiks of new bar
   if(Volume[0]>1) return;
//--- get Moving Average 
   maS0=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,0);
   maS1=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,1);
   maL0=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,0);
   maL1=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,1);
   ATR=iATR(NULL,0,ATRperiod,0);
//--- sell conditions
   if(maS1>maL1 && maS0<maL0 && ATRLevel<ATR)
     {
      res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,Bid+stoploss*ATR,Bid-takeprofit*ATR,"",MAGICMA,0,Red);
      return;
     }
//--- buy conditions
   if(maS1<maL1 && maS0>maL0 && ATRLevel<ATR)
     {
      res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,Ask-stoploss*ATR,Ask+takeprofit*ATR,"",MAGICMA,0,Blue);
      return;
     }
//---
  }
//+------------------------------------------------------------------+
//| OnTick function                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- check for history and trading
   if(Bars<100 || IsTradeAllowed()==false)
      return;
//--- calculate open orders by current symbol
   if(CalculateCurrentOrders(Symbol())==0) CheckForOpen();
//---
  }
//+------------------------------------------------------------------+
ダウンロード
MA+ATR.mq4
また2017.1.1-2018.1.1のJPYUSD5分足でバックテスト。
MA+ATR
一応右肩上がりになりました。
もうちょっとエントリー回数が欲しい気はしますが、移動平均線、ATRの期間やATRが0.1以上でエントリーや2.5倍でイグジットってのは多少最適化した時に出したものです。これ以上いじってもあまりよくなりそうにないかな…
ロット数の計算は付属のMoving Average.ex4のままなのでこのあたりもいじったほうがいいのかな…
実際に稼働させるまでにはまだまだかかりそうです。

移動平均線とRSIを条件でバックテスト

2018-05-25 22:16:15 | MT4(メタトレーダー4)
トレードの条件が移動平均線のクロスだけでは弱いようなので、
値動きの強弱が分かるらしいRSIを条件に追加してみます。
これは70以上なら買われすぎで売りシグナル、30以下なら売られ過ぎで買いシグナル、
というように逆張り指標として使われるっぽいです。


RSIの低い条件、高い条件、期間をRSIL,RSIH,RSIPeriodとして追加しましす。
//--- Inputs
input double Lots          =0.1;
input double MaximumRisk   =0.02;
input double DecreaseFactor=3;
input int    MovingPeriodS =7;
input int    MovingPeriodL =21;
input int    MovingShift   =6;
input int    RSIL          =30;
input int    RSIH          =70;
input int    RSIPeriod     =14;


エントリーにRSIの条件を追加します。
//+------------------------------------------------------------------+
//| Check for open order conditions                                  |
//+------------------------------------------------------------------+
void CheckForOpen()
  {
   double maS0;
   double maS1;
   double maL0;
   double maL1;
   double RSI;
   int    res;
//--- go trading only for first tiks of new bar
   if(Volume[0]>1) return;
//--- get Moving Average 
   maS0=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,0);
   maS1=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,1);
   maL0=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,0);
   maL1=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,1);
   RSI=iRSI(NULL,0,RSIPeriod,PRICE_CLOSE,1);
//--- sell conditions
   if(maS1>maL1 && maS0<maL0 && RSI>RSIH)
     {
      res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red);
      return;
     }
//--- buy conditions
   if(maS1<maL1 && maS0>maL0 && RSI<RSIL)
     {
      res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue);
      return;
     }
//---
  }

イグジットにもRSIの条件を追加します。
//+------------------------------------------------------------------+
//| Check for close order conditions                                 |
//+------------------------------------------------------------------+
void CheckForClose()
  {
   double maS0;
   double maS1;
   double maL0;
   double maL1;
   double RSI;
//--- go trading only for first tiks of new bar
   if(Volume[0]>1) return;
//--- get Moving Average 
   maS0=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,0);
   maS1=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,1);
   maL0=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,0);
   maL1=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,1);
   RSI=iRSI(NULL,0,RSIPeriod,PRICE_CLOSE,1);
//---
   for(int i=0;i<OrdersTotal();i++)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderMagicNumber()!=MAGICMA || OrderSymbol()!=Symbol()) continue;
      //--- check order type 
      if(OrderType()==OP_BUY)
        {
         if(maS1>maL1 && maS0<maL0 && RSI>RSIH)
           {
            if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,White))
               Print("OrderClose error ",GetLastError());
           }
         break;
        }
      if(OrderType()==OP_SELL)
        {
         if(maS1<maL1 && maS0>maL0 && RSI<RSIL)
           {
            if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,White))
               Print("OrderClose error ",GetLastError());
           }
         break;
        }
     }
//---
  }
ドル円5分足2017.1.1-2018.1.1でスタート!
結果は以前のMAのクロスだけの時
screenshot_52

よりエントリー回数が減って一瞬あがるもやはり右肩下がり…
screenshot_55

こうなりゃ最適化だ!とこんな条件でスタート!
screenshot_62

待つこと数時間。
利益でソートすると利益出したのもあるけど取引回数が少ない。
screenshot_63
screenshot_64

取引回数が多いもので利益出ててこれ。
う~んショボい。
難しいですね…
screenshot_65
screenshot_66



MT4バックテストの最適化

2018-05-20 13:08:30 | MT4(メタトレーダー4)
Moving Average.mq4を移動平均線のゴールドクロス・デッドクロスに改造
http://trading-fx.blog.jp/archives/9191662.html
では適当に短期と長期の期間を7と21を設定しました。
ここを最適化で変えてみたいと思います。

まずMT4を起動しメニューバーの【表示】→【ストラテジーテスター】でストラテジーテスターを表示。

screenshot_46

ストラテジーテスターの【エキスパート設定】をクリック。
緑のバーが出てるのは一度実行したからです。
screenshot_47

テスト設定では【遺伝的アルゴリズム】にチェックを入れると、
難しい原理はわかりませんが総当たりではなく高率のいい計算をして早く終わるらしいです。
最適化パラメーターは特にこだわりがなければ【Balance】のままでいいでしょう。
screenshot_48

パラメーターの入力タブでは変えたいMovingPeriodS,MovingPeriodLにチェックを入れ、
スタートとストップの値を入れます。
今回は試しにMovingPeriodS(短期)を6から始めて8、
MovingPeriodL(長期)を18から始めて22にしました。
あまり広い幅にすると時間がかかりますので注意。
ステップはいくつずつ増やすかです。今回は1つずつ増やしていますが2つずつなど飛ばして増やすこともできます。
screenshot_41

それが終わればOKをクリックして【最適化】にチェックを入れて【スタート】をクリック。
screenshot_42

しばらく待つと終わりの音が鳴りますので、【最適化結果】のタブを見てみましょう。screenshot_43

何も表示されない場合は右クリックをして【マイナスの結果を表示しない】のチェックを外してもう一度開始。
screenshot_50

上の【損益】をクリックすると損益の順にソートされます。
一番良くてもマイナスですね…
右の方を見るとその時の条件が分かります。
今回はMovingPeriodS=7、MovingPeriodL=22の時が一番マシという結果でした。
まあ、マシと言ってもマイナスなんですけどね…
screenshot_44

その行を選択してダブルクリックをすると【セッティング】タブに移行しその時のパラメーターがセットされますのでそのままスタートを押すとその設定でバックテストをしてくれます。
これ、もう一回テストしないと結果分からないんですかね…
screenshot_52

まあエントリーとイグジットの条件が移動平均線のクロスだけではちょっと難しいという事ですね。

右肩下がりの成績のEAって条件を逆にしたらいいんじゃね?

2018-05-13 00:16:42 | MT4(メタトレーダー4)
前回
Moving Average.mq4を移動平均線のゴールドクロス・デッドクロスに改造
http://trading-fx.blog.jp/archives/9191662.html
で移動平均線同士のクロスでエントリー・イグジットするEAを作りました。
しかしバックテストの結果は見事な右下がり…
screenshot_36
この条件でトレードするとダメという事ですね。
ん?じゃあこのエントリー・イグジットを逆にしたらどうなる?

という事で4か所書き換えて条件を逆に変えてみます。

ポジションを持つ条件を逆に変えます。
//+------------------------------------------------------------------+
//| Check for open order conditions                                  |
//+------------------------------------------------------------------+
void CheckForOpen()
  {
   double maS0;
   double maS1;   double maL0;   double maL1;  int    res;
//--- go trading only for first tiks of new bar
   if(Volume[0]>1) return;
//--- get Moving Average 
   maS0=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,0);   maS1=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,1);   maL0=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,0);   maL1=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,1);//--- sell conditions
   if(maS1>maL1 && maS0<maL0)     {
      res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red);
      return;
     }
//--- buy conditions
   if(maS1<maL1 && maS0>maL0)     {
      res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue);
      return;
     }
//---
  }
これの二か所を変えます。
//+------------------------------------------------------------------+
//| Check for open order conditions                                  |
//+------------------------------------------------------------------+
void CheckForOpen()
  {
   double maS0;
   double maS1;   double maL0;   double maL1;  int    res;
//--- go trading only for first tiks of new bar
   if(Volume[0]>1) return;
//--- get Moving Average 
   maS0=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,0);   maS1=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,1);   maL0=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,0);   maL1=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,1);//--- sell conditions
   if(maS1<maL1 && maS0>maL0)     {
      res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red);
      return;
     }
//--- buy conditions
   if(maS1>maL1 && maS0<maL0)     {
      res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue);
      return;
     }
//---
  }

お次は決済の条件。
//+------------------------------------------------------------------+
//| Check for close order conditions                                 |
//+------------------------------------------------------------------+
void CheckForClose()
  {
   double maS0;
   double maS1;
   double maL0;
   double maL1;
//--- go trading only for first tiks of new bar
   if(Volume[0]>1) return;
//--- get Moving Average   maS0=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,0);
   maS1=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,1);
   maL0=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,0);
   maL1=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,1);
//---
   for(int i=0;i<OrdersTotal();i++)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderMagicNumber()!=MAGICMA || OrderSymbol()!=Symbol()) continue;
      //--- check order type 
      if(OrderType()==OP_BUY)
        {
         if(maS1>maL1 && maS0<maL0)
           {
            if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,White))
               Print("OrderClose error ",GetLastError());
           }
         break;
        }
      if(OrderType()==OP_SELL)
        {
         if(maS1<maL1 && maS0>maL0)
           {
            if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,White))
               Print("OrderClose error ",GetLastError());
           }
         break;
        }
     }
//---
  }
これも二か所変えます。
//+------------------------------------------------------------------+
//| Check for close order conditions                                 |
//+------------------------------------------------------------------+
void CheckForClose()
  {
   double maS0;
   double maS1;
   double maL0;
   double maL1;
//--- go trading only for first tiks of new bar
   if(Volume[0]>1) return;
//--- get Moving Average   maS0=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,0);
   maS1=iMA(NULL,0,MovingPeriodS,MovingShift,MODE_SMA,PRICE_CLOSE,1);
   maL0=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,0);
   maL1=iMA(NULL,0,MovingPeriodL,MovingShift,MODE_SMA,PRICE_CLOSE,1);
//---
   for(int i=0;i<OrdersTotal();i++)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if(OrderMagicNumber()!=MAGICMA || OrderSymbol()!=Symbol()) continue;
      //--- check order type 
      if(OrderType()==OP_BUY)
        {
         if(maS1<maL1 && maS0>maL0)
           {
            if(!OrderClose(OrderTicket(),OrderLots(),Bid,3,White))
               Print("OrderClose error ",GetLastError());
           }
         break;
        }
      if(OrderType()==OP_SELL)
        {
         if(maS1>maL1 && maS0<maL0)
           {
            if(!OrderClose(OrderTicket(),OrderLots(),Ask,3,White))
               Print("OrderClose error ",GetLastError());
           }
         break;
        }
     }
//---
  }

これでエントリー・イグジットの条件が逆になりました。

さあ、それでバックテストをしてみた結果…









screenshot_37
ダメみたいですね…
そう単純にいかないものですね。