English Русский 中文 Español Deutsch Português
ヘッジ EA の検証でストラテジーテスタの限界を打ち破る

ヘッジ EA の検証でストラテジーテスタの限界を打ち破る

MetaTrader 4テスター | 15 3月 2016, 13:19
1 124 0
chayutra sriboonruang
chayutra sriboonruang

はじめに

本稿ではヘッジ EA をストラテジーテスタで検証する考えを提供します。ご存じのとおり、ストラテジーテスタには、別のシンボルについてのオーダーをオープンすることはできないという独自の限界があります。自分のヘッジ Expert Advisor を検証したいと思うユーザーは、本番で検証する必要があるのです。ですがこのことがわれわれの能力を制限するのでしょうか?ヘッジドレーダーはだれも本番のトレード以前に自分の EA を検証する必要がある、と私は思います。そのため、私は mt4 のストラテジーテスタの限界を打ち破るのに役立ち、将来の使用法に役立つと希望を持って、みなさんに仮想で戦略を検証動作(検証のような)を作成するという考えを提供しているのです。



仮想テスターのコンセプト

仮想テスターのアイデアが浮かんだのは、mq4の "Files" 関数で作業をしている時でした。仮想トレーディングスキームを設定するためにファイルから重要なデータを取り出すという考えが頭に浮かびました。「これはヘッジ EA を検証することについての答えになる可能性があるのでしょうか?」試してみようではありませんか。

私の仮想テスターは外部プログラムやソフトウェアを必要としません。すべてmq4 パラメータによって行うことができるのです。この仮想テスターのコンセプトは、ヘッジ注文のオープンやクローズの指定されたパラメータに必要なデータを集めるようわれわれに伝えさるというものです。始値、開始時刻、終値、終了時刻、その他すべての重要なデータです。必要なデータが設定されたら、それらは始値と最終ビッド、または始値と最終アスクのような互換性あるタイプの直近のティック値を比較するのに使用されます。そのような値は、ヘッジ終了条件を満たしたあと、データの新しいグループを集めさせる利益計算方法にわれわれを導くのです。

こういったデータグループはのちに使用するためにファイルにエクスポートされます。検証が完了し、データタイプがすべてファイルに集められると、『ヘッジ EA がどのように動作するか』確認します。パフォーマンス曲線のインディケータとしてデータをプロットするために、ファイルからデータを取得することでわれわれのヘッジ EA の視覚検証が完了したと考えられます。

このコンセプトで、現実のストラテジーテスタ結果に似た検証結果が得られると思われます。これがヘッジ Expert Advisor に対してテスターを作成する唯一の方法です。私は現実のテスターとまったく同じ結果が得られることは保証しません。ただのちに使用するために良い結果となるよう願うのみです。

それでは始めます。



ヘッジトレーディングの簡単な意味

スタート前に『ヘッジ』(ここにある私自身の pipsmaker という名前のブログからの抜粋です)。

ヘッジングを簡単に言うと、同時に 2 種類の通貨ペアの逆方向のトレードを 2 つオープンすることです。これはトレードリスクを低減します。片方が上昇すれば片方は確実に下降しますが、心配することはありません。なぜなら、同時に売りと買いの注文を出し、そのため片方で損を出してももう片方は利益を得るのです。それが『リスクを低減する』と言われるゆえんです。Forex 界では多種類の逆トレードスタイルがあります。

  • EURUSD と GBPUSD のようにつねに同じように変動する2組の通貨ペアで、同時に EURUSD の買いと GBPUSD の 売りをオープンするのがヘッジングです。
  • EURUSD と USDCHF のように常に逆に変動する 2 組の通貨ペアについては、EURUSD の買い、そしてUSDCHF の買いをオープンすることもヘッジすることになります。
  • または、同時に EURUSD の買いと売りをオープンすることもヘッジですが、これは『裁定』と呼ばれることもあります。

ヘッジ取引では疑いようのないことがいくつかあります。

  1. 相関関係とは、2 つの通貨間の統計的測定を言います。相関係数が取る範囲は -1 と +1 の間です。+1 の相関は2つの通貨ペアが 100% 同方向に変化することを意味します。-1 の相関は2つの通貨ペアが 100% 逆方向に変化することを意味します。相関ゼロは通貨ペア間の関係が完全にランダムであることを示します。(より詳しくはここを読んでください)こちらの無料ウェブサイト mataf.com,からも相関値を入手することができます。そこでは数多くの興味深いトレードパラメータも提供されています。
  2. ロットサイズ比率;同じ方向にも逆方向にも変動しない2つの通貨ペアに対して、ロット比率はひじょうに必要です。というのもそれら自身の変動性や変動能力は、片方がカメ、もう片方がうさぎとすれば、うさぎとカメほど異なるためです。より激しく変動するペア、すなわちうさぎペアによる影響を受け、カメペアに大きなロットサイズを設定することで、うさぎペアが負の動きをする場合に損失を低く抑え、ロット比率はリスクを低減します。そうすると、正のカメからより利益を得ることができる、別の言い方をすると、損失うさぎが出す損をカメの利益で置き換えが可能なのです。ヘッジのテクニックにより、負の側にトレードを一つだけオープンすることで出す以上の損失は受けなくてすむのです。

ところで、ヘッジャーがそのトレードスタイルからどのように利益を得るのだろう、と思ったことはありますか?ご心配なく。2組の通貨ペアにはつねに重複があります。事実上、相関関係は不変のスキームではありません。頻繁に1組による遅延があり、1組はそれを追います。ここでもまたうさぎとカメのようにです。うさぎが休憩し、カメが打ち負かし勝利するのを待つのです。ヘッジャーがそこからすてきな利益を得るのはそのためです。そして今、数多くの人が Forex で利益を得るためにヘッジスタイルを利用しています。心配することは何もありません。ヘッジし、待ち、利益が示されたらクローズする。それだけです。



ヘッジのコンセプト

仮想テスターをコード化するにさきがけ、実験でヘッジのコンセプトを理解しておきます。ヘッジコンセプトの知識なしでは、どのタイプのデータをエクスポートし、レコードし、計算するかわかりません。こういったデータはどのタイプのオーダーがバーチャルで作成されるか示してくれます。この実験では、以下のようにヘッジのルールを設定します。

  • 1日の始まりに毎日ヘッジを開始する。
  • $100 に到達すれば終了する(ロットサイズ 1 と 2 を取ります)。
  • 毎時ティック価格データを収集する***
  • 目標利益に到達していなくても、翌日の始めにはそのデータをクリアする。
  • EURJPY を 2 ロットだけ買い、GBPJPY を 1 ロット売る。

このルールに従い、仮想オーダーには毎日注文の始値として使用される開始価格(両ペアの)が必要です。1日の利益を計算するには、日々毎時のティック価格が終値(売りに対するアスク、買いに対するビッド)に対するデータとして、ティック時刻と共に記録される必要があります(ティック価格が同じ時刻値からのものであることを確認するため)。日次でヘッジを開始するコンセプトにより、必要なデータを2種類のファイルタイプに分けます。2組のペアの日次開始値とティック値のファイルです。2種類のデータタイプはどちらも文字列ファイルとして別の名前でエクスポートします。GBPJPYD1.csv と GBPJPYTick.csv などです。

仮想テスターが現実のテスターにできるだけ似たものとなるよう、望んだティックデータのために、以下の 2 ステップを行う必要があります。

  • GBPJPY の始値を毎日ファイルにエクスポートするためのスクリプト作成
  • GBPJPY のティック価格を毎日ファイルにエクスポートするためのスクリプト作成

どちらのステップも EURJPY に対しても行う必要があります。

ですが、私は両方を1件の expert advisor に融合することができると思います。この EA は 2 タイプのデータを 別個のファイル 2 件にエキスポートするのです。この EA がデータ記録処理を終えたら、仮想取引を作成する新規の EA が仮想検証を行うためにエキスポートされた全ファイルから GBPJPY と EURJPY 両方のデータをすべて取得します。



検証の限界を打ち破る 3 ステップ

上記の考えにより、私は、この限界を破るというわれわれの夢は以下の3ステップで実現可能であるという結論に達しました。

  1. 価格データを取り、EA を使用してそれをファイルに出力する。
  2. 結果をファイルとしてエクスポートする別の EA で仮想取引を作成する。
  3. 結果を別ウィンドウでインディケータとして再検討する。

では、第1ステップを始めます。



ステップ1:価格データをエクスポートする。

以下はアタッチされたシンボルのファイルへの日次始値をエクスポートする Expert Advisor です。GBPJPY に対して "GBPJPYD1.csv" 、EURJPY に対して "EURJPYD1.csv" と名付けられています。にファイルにティック価格もエクスポートします。それは"symbolT.csv" (D1 ファイルに同じ)のように名付けられます。EA がどのように動作するか学ぶためにコメントを読んでください。

注意:この EA により作成されるファイルはすべて "MetaTrader 4/tester/files" ディレクトリにエクスポートされます。

//+------------------------------------------------------------------+
//|                                                    symbol-D1.mq4 |
//|                                                    A Sexy Trader |
//|                                  http://pipsmaker.wordpress.com/ |
//+------------------------------------------------------------------+
#property copyright "A Sexy Trader"
#property link      "http://pipsmaker.wordpress.com/"
#include <stdlib.mqh>
 
extern string StartDate = "2007.03.17"   //set the starting date to get the same time data
             ,StopDate  = "2007.06.28";  //set the testing time limit to protect the over 
                                         //data recording process
 
extern bool For_OP_SELL = true;/*This is to guide for the right type of data to be collected
                                 ->if For_OP_SELL = true
                                   the daily Open will be collected as an order open price
                                 ->if For_OP_SELL = false , means for OP_BUY,
                                   the daily Open+SPREAD will be collected instate.
                               */
                               
string name,tname;
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
//----
 
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   
//----
   return(0);
  }
//-------------------------------------------------------------------+
//| Some Essential Parameters In This EA                             |
//-------------------------------------------------------------------+
   int day                   // a variable to mark that today Open has been collected 
      ,ho                    // handle of the file recording the Open price 
      ,ht                    // handle of the file recording the tick price
      ,x=1                   /* the order of D1 file increasing every time D1 data is
                             equal to 4086 characters and generate the new recording file*/
      ,xt=1                  // same as x but for tick data
      ,bartime               // a variable to mark that current bar's Open has been collected 
      ;
   double ot                 // latest Open Time
         ,op                 // latest Open price
         ,lt                 // latest tick time
         ,ltk                // latest tick price
         ;
   string OStr               // the string to collect the daily open
         ,TStr               // the string to collect the tick value
         ;
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
    
    /*---------------------Only collect the data in the specific time period.----------------------*/
    if(TimeToStr(TimeCurrent(),TIME_DATE)>=StartDate && TimeToStr(TimeCurrent(),TIME_DATE)<=StopDate)
    {
       name=Symbol()+x+"D1.csv";       // setup the name of daily open price file
       tname=Symbol()+xt+"T.csv"       // the name of tick price file
            ;
//----       
      if(day!=TimeDay(Time[0]))        // the new day has come
       {
         ot=Time[0];                   // get the new bar time
         if(For_OP_SELL)op=Open[0];    // get the new order open price for SELL Symbol 
                                                 
         else           op=Open[0]+MarketInfo(Symbol(),MODE_SPREAD)*Point;
                                       // else if collecting for the BUY Symbol
         

         OStr=OStr+TimeToStr(Time[0],TIME_DATE)+",";//collect the new time data separate each data with ","
         OStr=OStr+DoubleToStr(op,Digits)+",";      //now the new open price
       
       //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~now it's time to export as a file 
       
       ho=FileOpen(name ,FILE_CSV|FILE_WRITE);  // open a file to record the daily open
       if(ho>0)                                 // if the file Symbol()+x+"D1.csv" exist
       {
        FileWrite(ho,OStr);                     // write the collected data
        FileClose(ho);                          // close the file every time your file process done
        if(StringLen(OStr)==4086){x++;OStr="";} /* if the data contains 4086 characters set new x to*/
       }                                        /*   create the new file and prepare the new string for
                                                   the new file
                                                */
        
       Print(TimeToStr(Time[0],TIME_DATE));     // print the collected day time 
       
       int thex=FileOpen(Symbol()+"x.csv",FILE_CSV|FILE_WRITE);
                                                // create a file to record "how many x?" for D1 file for further usage
       if(thex>0)                               // if the file exist
       {
        string xs=DoubleToStr(x,0);             // transform x into string 
        FileWrite(thex,xs);                     // write the x value
        FileClose(thex);                        // close file (every time you finish)
       }
        

        day=TimeDay(Time[0]);                   // now mark today as collected 
       }
 
//--------------------------------FOR TICK VALUE
       /*Because of the decision of collecting the tick data hourly*/
       if(bartime!=Time[0])                     // the new hourly bar has come
                                                // and to make it more flexible when you decided 
                                                      // to collect data in another time frame
       {
         lt=TimeCurrent();                      // get the tick time 
         
         if(!For_OP_SELL) ltk=Bid;              // the tick price for sell order 
         else             ltk=Ask;              // in case for buy order
         
         TStr=TStr+TimeToStr(lt,TIME_DATE|TIME_MINUTES)+",";
                                                // insert the data into the collected string 
         TStr=TStr+DoubleToStr(ltk,Digits)+","; //
         
       //~~~~~~~~                               // now export the data 
       ht=FileOpen(tname,FILE_CSV|FILE_WRITE);  // open a file to record the tick value
       if(ht>0)                                 // if the file Symbol+xt+"T.csv" exist
       {
        FileWrite(ht,TStr);                     // write the collected tick with time 
        FileClose(ht);                          // finish.
        if(StringLen(TStr)==4080){xt++;TStr="";}// prepare for new file if this file reached 4080 character
       }
       
       int thext=FileOpen(Symbol()+"xt.csv",FILE_CSV|FILE_WRITE);
                                                // record the xt value .. same as D1 file 
                                                
       if(thext>0)                              // if the file exist
       {
        string xts=DoubleToStr(xt,0);           // transform into string 
        FileWrite(thext,xts);                   // write xt
        FileClose(thext);                       // done
       }
     bartime=Time[0];                           // mark as current hourly bar Open price has been collected
     }
   }
   else if(TimeToStr(TimeCurrent(),TIME_DATE)>StopDate)  // if out of specified period  
   Print("Done.");                                       // let us know it all done.
//----
   return(0);
  }
//+------------------------------------------------------------------+



ステップ 2:仮想取引を作成する

このステップは一番テンションが上がる部分です。ストラテジーテスタで検証可能なヘッジ EA を作成するステップです。表記がどのようなものか以下のスクリプトをご覧ください。そして、それがどのように動作するか理解するためコメントを忘れずに読みます。最初の EA 同様、結果ファイルはMetaTrader 4/tester/files" ディレクトリにエクスポートされます。

//|                                                 VirtualHedge.mq4 |
//|                                                    A Sexy Trader |
//|                                  http://pipsmaker.wordpress.com/ |
//+------------------------------------------------------------------+
#property copyright "A Sexy Trader"
#property link      "http://pipsmaker.wordpress.com/"
#include <stdlib.mqh>
 
extern string  StartDate         = "2007.03.17";    // specify the testing period the same as collected data
extern string  StopDate          = "2007.06.27";
extern string  BaseSymbol        = "GBPJPY";        // the base symbol          
extern string  HedgeSymbol       = "EURJPY";        // the hedge symbol
 
extern int     Base_OP           = OP_SELL;         // by the rules always sell GBPJPY
extern int     Hedge_OP          = OP_BUY;          // and always buy EURJPY
 
extern double  BaseLotSize       = 1.0;             // take the lot size of 1 for GBPJPY
extern double  HedgeLotSize      = 2.0;             // and take 2 lots for EURJPY
 
extern double  ExpectProfit$     = 100;             // always close when reach $100
 
extern bool    PrintDetails      = true;            // print the order opening and closing detail ?
 
int BSP                                      // the spread of GBPJPY 
   ,HSP                                      // the spread of EURJPY
   ,BOP=-1                                   // OrderType of GBPJPY
   ,HOP=-1                                   // OrderType of EURJPY
   ,day=0                                    // for marking that today hedge was executed
   ,hr                                       // handle of the file for exporting the hedge result
   ,p=1
   ,BC                                       // the base-symbol's contract size
   ,HC                                       // the hedge-symbol's contract size
   ,floating=0                               // for marking as there are some orders currently floating
   ,Pointer=0                                // the Pointer of each string data
   ,AL                                       // Account Leverage
   ,on                                       // order number
   ;
double BOpen                                 // open price of base symbol
      ,HOpen                                 // open price of hedge symbol
      ,BLots                                 // base symbol lotsize
      ,HLots                                 // base symbol lotsize
      ,lastTick                              // to mark the last tick for calculating the current profit
      ,BPF                                   // base symbol order profit
      ,HPF                                   // hedge symbol order profit
      ,TPF                                   // the total profit
      ,CurBalance                            // the array to collect the hedge results
      ,CurB=0                                // the current balance
      ,BTick                                 // Base tick
      ,HTick                                 // Hedge tick
      ,BD1Time                               // Base daily open time 
      ,HD1Time                               // Hedge daily open time 
      ,BTTime                                // Base tick time 
      ,HTTime                                // Hedge tick time 
;
 
string CurTrade                              // a string to show the current performance as a comment 
      ,BORD                                  // a string to specify the type of arrows and text of base symbol
      ,HORD                                  // same thing but for hedge symbol                   
      ,hobstr                                // the whole string of the base symbol open price data
      ,bstr                                  // the string of all daily data of base Symbol 
      ,hstr                                  // the string of all daily data of hedge Symbol
      ,btstr                                 // the string of tick data of base Symbol
      ,htstr                                 // the string of tick data of hedge Symbol
      ,pstr                                  // the string for exporting result data
      ;
 
color SELLCL=DeepSkyBlue                     // the color of arrows to mark that sell order was executed
     ,BUYCL=HotPink                          // the color of arrows to mark that buy order was executed
     ,BCL                                    // the color of base symbol, varies by the Base_OP parameter
     ,HCL                                    // the color of hedge symbol, varies by the Hedge_OP parameter
     ;
     
bool closed=true                             // for marking as all trades were closed
     ,trimb=true                             // get rid of taken data of base Symbol or not?
     ,trimh=true                             // get rid of taken data of hedge Symbol or not?
     ,trimbd1=true                           // get rid of taken daily data of base Symbol or not?
     ,trimhd1=true                           // get rid of taken daily data of hedge Symbol or not?
     ;     
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
//----
   CurBalance=AccountBalance();                      //mark the initial deposit
   CurB=AccountBalance();                            //mark the current balance
   pstr=pstr+DoubleToStr(CurBalance,2)+",";          //collect the performance string
   
   AL=AccountLeverage();                             //get the Account Leverage
   
   BSP=MarketInfo(BaseSymbol  ,MODE_SPREAD);         //get the spread
   HSP=MarketInfo(HedgeSymbol ,MODE_SPREAD);
   
   BC =MarketInfo(BaseSymbol  ,MODE_LOTSIZE);        //get the contract size for calculating profit
   HC =MarketInfo(HedgeSymbol ,MODE_LOTSIZE);
   
   BOP=Base_OP;                                      //get the OrderType 
   HOP=Hedge_OP;
   
   BLots=BaseLotSize;                                //get the lot size
   HLots=HedgeLotSize;
   
   string RName=BaseSymbol+"_"+HedgeSymbol+"_result"+p+".csv";
                                                     //name the performance file
                                                     //this file is needed to copy to 
                                                     /* Program files/MetaTrader 4 /Experts/files */
   
   hr =FileOpen(RName ,FILE_CSV|FILE_WRITE);         //open the file to export the initial deposit
 
   if(hr>0)                                          //if the file exist
   {
    FileWrite(hr,pstr);                              //export the initial deposit
    FileClose(hr);                                   //close file
   }
   
   if(Base_OP==OP_SELL){BCL=SELLCL;BORD="sell";}     //specify the parameter leading to create 
   else                {BCL=BUYCL; BORD="buy";}      // the trading arrow and text
   if(Hedge_OP==OP_BUY){HCL=BUYCL; HORD="buy";}
   else                {HCL=SELLCL;HORD="sell";}
   
   getdata(BaseSymbol);                              //get all data of BaseSymbol
   getdata(HedgeSymbol);                             //all data of HedgeSymbol
                                                     //the function located at the bottom 
   return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
string RName=BaseSymbol+"_"+HedgeSymbol+"_result"+p+".csv"; //name the performance file
 
//--------------------------Only perform the show of specified period--------------------------// 
if(TimeToStr(TimeCurrent(),TIME_DATE)>=StartDate && TimeToStr(TimeCurrent(),TIME_DATE)<=StopDate)
                                                                               //mark as no any order now
{
 if(day!=TimeDay(Time[0]))                                  //the new day has come
 {
  
  {
   if(BOpen!=0 && HOpen!=0)                                 //check if yesterday hedge still floating
   {
 
    if(Base_OP==OP_BUY)                                     //the base-symbol's current profit
     {
      BPF=((BTick-BOpen)*BLots*BC)/BOpen;
     }
    else
    {
     BPF=((BOpen-BTick)*BLots*BC)/BOpen;
    }
    
    if(Hedge_OP==OP_BUY)                                    //the hedge-symbol's current profit
    {
     HPF=((HTick-HOpen)*HLots*HC)/HOpen;
    }
    else
    {
     HPF=((HOpen-HTick)*HLots*HC)/HOpen;
    }
    
    TPF=BPF+HPF;                                            //the total current profit
    
    CurB+=TPF;
    
    CurBalance=CurB;                                        //get the latest AccountBalance
    
    pstr=pstr+DoubleToStr(CurBalance,2)+",";                //insert into the performance string
    
    floating=0;                                             //mark as no any order now
 
    BOpen=0;                                                // block the profit calculation process
    HOpen=0;
    
    if(BOpen==0 && HOpen==0)                                //make sure there is no any order now
    {
     closed=true;                                           //mark all orders were closed
     
     CreateObject("R : "+on,OBJ_TEXT,Time[0],Close[0],0,0,DarkViolet,"","Cleared With Profit Of : "+DoubleToStr(TPF,2));
                                                            //create the cleared all orders text
     
     if(PrintDetails)Print("Cleared Hedge With Profit : "+DoubleToStr(TPF,2));
                                                            //print latest action if PrintDetails allowed
                                                            
      hr =FileOpen(RName ,FILE_CSV|FILE_WRITE);             //open the result file to prepare for file writing
      if(hr>0)
      {
       FileWrite(hr,pstr);                                  //export the data
       FileClose(hr);
      }
      if(StringLen(pstr)>4086){p++;pstr="";}                //set the new file name if pstr is larger than 4086 characters
    


      int thep=FileOpen("p.csv",FILE_CSV|FILE_WRITE);       //this file is needed to copy to 
                                                            /* Program files/MetaTrader 4 /Experts/files */
                                                            //too
                                                            
                                                            // record the p value as a file 
                                                
       if(thep>0)                                           // if the file exist
       {
        string ps=DoubleToStr(p,0);                         // transform into string 
        FileWrite(thep,ps);                                 // write p
        FileClose(thep);                                    // done
       }
    
    }
   }
   
   if(floating==0)                                          //now all yesterday hedge were cleared 
   {
    trimb=true; trimh=true;                                 //allow getting tick data for today to work
       

    //----------GETTING TODAY ORDER OPEN PRICE AND TIME----------//  
         if(trimbd1)                                              //getting the daily base price allowed
         {
             Pointer=StringFind(bstr,",",0);                      //find the nearest "," from the beginning of string
             BD1Time=StrToTime(StringSubstr(bstr,0,Pointer));     //get the time value located before the "," syntax
             bstr=StringSubstr(bstr,Pointer+1,0);                 //trim off the taken data
             
             Pointer=StringFind(bstr,",",0);                      //find the nearest "," from the trimmed data string
             BOpen=StrToDouble(StringSubstr(bstr,0,Pointer));     //get the PRICE value located before the "," syntax
             bstr=StringSubstr(bstr,Pointer+1,0);                 //trim off the taken data again to prepare for next time 
         }
         if(trimhd1)                                              //getting the daily hedge price allowed
         {
             Pointer=StringFind(hstr,",",0);                      //all processes are the same as bstr above
             HD1Time=StrToTime(StringSubstr(hstr,0,Pointer));     //...
             hstr=StringSubstr(hstr,Pointer+1,0);                 //...   
             
             Pointer=StringFind(hstr,",",0);                      //...
             HOpen=StrToDouble(StringSubstr(hstr,0,Pointer));     //...
             hstr=StringSubstr(hstr,Pointer+1,0);                 //...
         }
    //--------GETTING TODAY ORDER OPEN PRICE AND TIME ENDED--------//  
 

       if(BOpen!=0 && HOpen!=0 && CurBalance>(BLots+HLots)*BC/AL)
               //make sure the data taken is not zero and margin balance still available    
       {
       floating=1;            //mark as hedge sent
       
       closed=false;          //mark as all orders opened
       
       on++;                  //new hedge orders have opened 
        
        if(PrintDetails)      //if PrintDetails allowed
        {
         Print(on+" Opened : "+BaseSymbol+" "+DoubleToStr(BLots,2)+" lots @ "+DoubleToStr(BOpen,Digits)+".");
         Print(on+" Opened : "+HedgeSymbol+" "+DoubleToStr(HLots,2)+" lots @ "+DoubleToStr(HOpen,Digits)+".");
        }
       }
       else                                                 //in case can not send hedge
       {
        Comment("Can Not Open The Trade : No Margin Available");
       }                                                    //let us know 
       

       if(closed==false)                                    //hedge sent
       {
                                                            //create the buy and sell arrow and text
                                                            //this function is located at the bottom of the EA
       CreateObject("B : "+on,OBJ_ARROW,Time[0],Open[0]-20*Point,0,0,BCL,BORD,"");
 
       CreateObject("H : "+on,OBJ_ARROW,Time[0],Open[0]+30*Point,0,0,HCL,HORD,"");
       }
   }
  }
  
  day=TimeDay(Time[0]);                                     //mark as proceeded
 }
 
//-------------------------For Each Tick----------------------------// 
 
if(lastTick!=Hour())                 //the new hour has come
{
  
   if(trimb && StringFind(btstr,",",0)>0)                         //getting base tick allowed
   {
             Pointer=StringFind(btstr,",",0);                     //same process as getting daily data above
             BTTime=StrToTime(StringSubstr(btstr,0,Pointer));
             btstr=StringSubstr(btstr,Pointer+1,0);
             
             Pointer=StringFind(btstr,",",0);
             BTick=StrToDouble(StringSubstr(btstr,0,Pointer));
             btstr=StringSubstr(btstr,Pointer+1,0);
   }
   if(trimh && StringFind(htstr,",",0)>0)                         //if getting hedge tick allowed
   {
             Pointer=StringFind(htstr,",",0);
             HTTime=StrToTime(StringSubstr(htstr,0,Pointer));
             htstr=StringSubstr(htstr,Pointer+1,0);
             
             Pointer=StringFind(htstr,",",0);
             HTick=StrToDouble(StringSubstr(htstr,0,Pointer));
             htstr=StringSubstr(htstr,Pointer+1,0);
   }
  


  if(TimeDay(BD1Time)==TimeDay(BTTime) && TimeDay(HD1Time)==TimeDay(HTTime))
                                                            //only if the tick is form the same day
  {
   trimbd1=true; trimhd1=true;                              //allow to get the next day value
   
   if(TimeHour(BTTime)==TimeHour(HTTime))                   //and same time hour
   {
     
     trimb=true; trimh=true;                                //allow to get the next tick value
 
     if(BOpen!=0 && HOpen!=0)                               //if the calculation process allowed
     {
      
      if(Base_OP==OP_BUY)
       {
        BPF=((BTick-BOpen)*BLots*BC)/BOpen;                 //the base-symbol's current profit
       }
      else
      {
       BPF=((BOpen-BTick)*BLots*BC)/BOpen;
      }
    
      if(Hedge_OP==OP_BUY)
      {
       HPF=((HTick-HOpen)*HLots*HC)/HOpen;                  //the hedge-symbol's current profit
      }
      else
      {
       HPF=((HOpen-HTick)*HLots*HC)/HOpen;
      }
     
      TPF=BPF+HPF;                                          //the total current profit
      
      CurTrade=DoubleToStr(TPF,2);                          //show the current profit
     
      if(TPF > ExpectProfit$)                               //when they need to close  
      {
       
       BOpen=0;                                             //set the new value of order open price 
       HOpen=0;                                             //and block the profit calculation process
      
       CurTrade="No Any Hedge Order Now.";                  //Hedge was closed 
       

       floating=0;                                          //mark as hedge was closed
       CurB+=TPF;
       
       CurBalance=CurB;                                     //get the last balance equity
       
       pstr=pstr+DoubleToStr(CurBalance,2)+",";             //insert into performance string
       
       CreateObject("R : "+on,OBJ_TEXT,Time[0],Close[0],0,0,YellowGreen,"",
                                 "Close With Profit Of : "+DoubleToStr(TPF,2));
                                                            //create the closed text
                                                            
       if(PrintDetails)                                     //Print the last Close detail
       {
         Print(on+" Closed "+BaseSymbol+" @ "+DoubleToStr(BTick,Digits));
         Print(on+" Closed "+HedgeSymbol+" @ "+DoubleToStr(HTick,Digits));
         Print(on+" Closed Hedge With Profit : "+DoubleToStr(TPF,2));
       }
       hr =FileOpen(RName ,FILE_CSV|FILE_WRITE);    //open it again to prepair for file writing
       
       if(hr>0)
       {
        FileWrite(hr,pstr);                         //export the data
        FileClose(hr);
       }
      
      if(StringLen(pstr)>4086){p++;pstr="";}        //set the new file name if pstr is larger than 4086 characters
       

       thep=FileOpen("p.csv",FILE_CSV|FILE_WRITE);
                                                    // record the p value again
                                                
       if(thep>0)                                   // if the file exist
       {
        ps=DoubleToStr(p,0);                        // transform into string 
        FileWrite(thep,ps);                         // write p
        FileClose(thep);                            // done
       }
      
      }
     }
     
   }
   else                                             //in case the data values are not from the same tick time  
   {
     if(BTTime>HTTime){trimb=false;}                //freeze the offside data to can not be trim off
     
     else             {trimh=false;}
   }
  }
  else                                              //in case tick data is offside from today
  {
     if(BTTime>BD1Time){trimb=false;}               //freeze the offside data to can not be trim off
     else
     if(BTTime<BD1Time){trimbd1=false;}
      
     if(HTTime>HD1Time){trimh=false;}
     else
     if(HTTime<HD1Time){trimhd1=false;}
  } 
}
 


lastTick=Hour();                                     //mark as latest tick proceeded
}
   

   Comment("\nBOpen : "+DoubleToStr(BOpen,Digits)    //show the current situation
          ,"\nHOpen : "+DoubleToStr(HOpen,Digits)
          ,"\nBOT : "+TimeToStr(BD1Time,TIME_DATE)
          ,"\nHOT : "+TimeToStr(HD1Time,TIME_DATE)
          ,"\nBTick : "+DoubleToStr(BTick,Digits)
          ,"\nHTick : "+DoubleToStr(HTick,Digits)
          ,"\nBTT : "+TimeToStr(BTTime,TIME_DATE|TIME_MINUTES)
          ,"\nHTT : "+TimeToStr(HTTime,TIME_DATE|TIME_MINUTES)
          ,"\nfloating : "+floating
          ,"\nclosed : "+closed
          ,"\ntrimb : "+trimb
          ,"\ntrimh : "+trimh
          ,"\n"
          ,"\nCurOrderNo. : "+on
          ,"\nCurProfit : "+CurTrade
          ,"\nCurBalance : "+DoubleToStr(CurBalance,2)
          );
//----
   return(0);                                               //ALL DONE.
  }
//+------------------------------------------------------------------+
//| A Function To Make This Virtual Tester Looks Like The Real One   |
//+------------------------------------------------------------------+
void CreateObject(string name,int type, int time1, double price1, int time2,
                             double price2, color cl,string ordtype,string txt)
{
    
    if(type==OBJ_TREND)
    {
    ObjectCreate(name,type,0,time1,price1,time2,price2);
    ObjectSet(name,OBJPROP_COLOR,HotPink);
    }
    
    if(type==OBJ_ARROW)
    {
    ObjectCreate(name,type,0,time1,price1);
    ObjectSet(name,OBJPROP_COLOR,cl);
     if(ordtype=="sell")ObjectSet(name,OBJPROP_ARROWCODE,221);
     else              ObjectSet(name,OBJPROP_ARROWCODE,222);
    }
 
    if(type==OBJ_TEXT)
    {
     ObjectCreate(name,type,0,time1,price1);
     ObjectSetText(name,txt,8,"Comic Sans MS",cl);
    }
}
//+------------------------------------------------------------------+
//| GETTING ALL DATA FROM FILES FUNCTION                             |
//+------------------------------------------------------------------+
void getdata(string sym)
{
Comment("Collecting Data.","\n\nPlease Wait........");  //let us know that getting data still in process
      
      int x =FileOpen(sym+"x.csv",FILE_CSV|FILE_READ)   //get how many files of D1 and tick
         ,xt=FileOpen(sym+"xt.csv",FILE_CSV|FILE_READ)
         ,pter=0,s=0,v=0
         ,lastME=0,t=0
         ;
      double ME,U;
      string str,str2;
      int xa=StrToInteger(FileReadString(x))
         ,xta=StrToInteger(FileReadString(xt))
         ,xtc=1
         ;
      FileClose(x);
      FileClose(xt);
   
      if(xta>xa)xtc=xta;                                     //make it run only in one for loop
      else      xtc=xa;
      
      pter=0;s=0;
      for(int i=1;i<=xtc;i++)                                //the loop to get all string data
      {
       string name=sym+i+"T.csv"                             //set the data file name
             ,d1  =sym+i+"D1.csv"
             ;
       int h=FileOpen(name,FILE_CSV|FILE_READ)               //open all files to read
          ,d=FileOpen(d1  ,FILE_CSV|FILE_READ);
       
       //------------------------------------------------------------
       string source=FileReadString(h);                      //read the tick string
       FileClose(h);
       
        if(sym==BaseSymbol)                                  //if get the data of base symbol 
        {
         btstr=btstr+source;
        }
        else                                                 //if hedge symbol 
        {
         htstr=htstr+source;
        }
 
       //------------------------------------------------------------
       if(d>0)                                               //read the daily data 
       {
         string d1s  =FileReadString(d);FileClose(d);
         
         if(sym==BaseSymbol)                                 //if get base daily data
         {
          bstr=bstr+d1s;
         }
         else                                                //if get hedge data
         {
          hstr=hstr+d1s;
         }
       }
      }
}
//------------------------------------ALL DONE---------------------------------------------//


ステップ 3:結果を見直す

仮想オーダーが実行され、ヘッジ結果が記録されると、われわれのヘッジコンセプトを明示するためデータを取り込みます。そのために、私はCCI、RSI、ATR など数多くのインディケータのように、別ウィンドウにパフォーマンス曲線をプロットするためのインディケータとして記録されたデータをエクスポートすることにしました。そして、2 番目の EA から得るファイルをすべて "MetaTrader 4/experts/files" ディレクトリにコピーしました。

この曲線を終了するためには以下のインディケータを必要とします。

//+------------------------------------------------------------------+
//|                                                  performance.mq4 |
//|                                                    A Sexy Trader |
//|                                         http://pipsmaker.wordpress.com/ |
//+------------------------------------------------------------------+
#property copyright "A Sexy Trader"
#property link      "http://pipsmaker.wordpress.com/"
 
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 Goldenrod
//---- input parameters
extern string    BaseSymbol="GBPJPY";
extern string    HedgeSymbol="EURJPY";
//---- buffers
double ExtMapBuffer1[]                 //this is the indicator buffer
      ,curve[8888888]                  //this array is for collecting the result from the performance file
      ;
 
int handle;                            //maybe no need to explain anymore
string data;
int len=0
   ,i=0
   ,j=0
   ,p
   ,pv
   ,pter=0
   ;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- indicators
   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0,ExtMapBuffer1);
   
   IndicatorShortName(BaseSymbol+"~"+HedgeSymbol+" ");
//----
   
   p =FileOpen("p.csv",FILE_CSV|FILE_READ);                       //get how many result files were exported
   pv=StrToInteger(FileReadString(p));
   FileClose(p);
   
   for(int i=1;i<=pv;i++)                                         //the loop to get all exported result as a string
   {
      string name = BaseSymbol+"_"+HedgeSymbol+"_result"+p+".csv";//get the name of the performance file
      handle=FileOpen(name,FILE_CSV|FILE_READ);                   //search for the file to open to read
      if(handle>0)                                                //if the file is exist
      {
          data=data+FileReadString(handle);                       //get the whole data
          FileClose(handle);                                      //close it
      }
   
   }
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int    counted_bars=IndicatorCounted(),i=0,s=-1;
   
//----
   len=StringLen(data);                              //get the lenght of the data string
  
   pter=0;                                           //set the pointer which use for searching the ","
                                                     /*please be informed that the file csv was collected
                                                     the result as a string like this
                                                     1000.54,1100.54,1200.54,1300.54,1400.54
                                                     but the fact is we want only the real data is like this
                                                     1000.54
                                                     1100.54
                                                     1200.54
                                                     1300.54
                                                     1400.54
                                                     so the "," is the key to get the data as above
                                                     and it can be done by finding out the data befor ","
                                                     and get rid off it from the whole data
                                                     to shift the next data into the front
                                                     and insert each taken off data into the curve array
                                                     */
   
   for(i=len;i>=0;i--)                               /*the loop to define how many room this array should build
   {                                                   to contain the performance data
                                                     */
    if(StringFind(data,",",0)>0)                     //if there is a nearest "," from the front
    {
     s++;                                            //indicate the room number  
     pter=StringFind(data,",",0);                    //get the point where the first "," exist
     curve[s]=StrToDouble(StringSubstr(data,0,pter));//insert the first data of the whole string
     data=StringSubstr(data,pter+1,0);               //cut the inserted data off
    }
    else          break;                             //no data to count anymore , break the loop
 
   ArrayResize(curve,s+1);                           //resize the curve array for furthur usage
//----
   for(i=0,j=s;i<=s;i++,j--)                         //the plotting process bigin
   {
    if(curve[j]>0)ExtMapBuffer1[i]=curve[j];         //plot the performance curve
   }
//----                                               //all the things done.
 
   return(0);
  }
//+------------------------------------------------------------------+


利用方法

私のコードのコピーをダウンロードする前に、ミニユーザーマニュアルとして、『利用方法』を簡潔に説明します。

期待を現実のものとするためには、必須の簡単なステップが5つあります。以下がそれです。

  1. テスター(仮想モードである必要はありません)では、"Expert Advisor:" メニューで symbol-D1.mq4 を選択します。そして "Symbol:" でお好みのヘッジペアの最初のヘッジシンボルを選択し、日時で期間を設定し、このシンボルが売り注文なら"For_OP_SELL" 値を真に、このシンボルが買い注文なら偽に設定します。「周期」メニューで毎時の周期を選択し、記録処理を実行するために『開始する』をクリックします。
  2. 2番目のヘッジシンボルに対してもステップ1同様に行います。このシンボルのオーダータイプに合わせるため、***パラメータ "For_OP_SELL" の変更を忘れないでください***
  3. VirtualHedge.mq4 を選択し、変数をすべて設定したら、検証シンボルを選択します(お望みのシンボルはなんでも結構です)。ただ、ヘッジのパフォーマンスを確認するにはビジュアルモードが必要です。
  4. ヘッジのパフォーマンスを示す関連ファイルをすべてディレクトリ "program files/metatrader 4/tester/files"から "program files/metatrader 4/experts/files" コピーします。(すべてをコピーするのに2つ以上のファイルを必要とする場合は、 GBPJPY_EURJPY_result1.csv と p.csv を含みます。)
  5. performance.mq4 を現在アクティブとなっている任意のチャートにアタッチし、現実に近いヘッジのパフォーマンスを確認します。

以下が私の実験ルールによるパフォーマンス曲線です。

おやおや!見やすいものではないですね。みなさんの結果はもっと良いものになっていると思います。



おわりに

私はヘッジ EA を検証する新たな一歩が踏み出せたことをうれしく思っています。テスターの限界はもうヘッジャーにとっても問題ではありません。ところで、 本稿におけるヘッジングのコンセプトは一例にすぎず、検証時間のプロセスを短くするために作成したものです。 みなさんのヘッジ戦略のために仮想テスターを作成するには、始値、終値、高値、安値その他タイプの重要なデータをリストアットする必要があります。相関関係を使ってトレードする場合は、各指定時刻のすべての相関値もエクスポートする必要があります。このリストにより、どのデータが記録され、計算され、また結果として出力されるべきか知ることになります。データ処理時間を短縮するために、検証期間期を小さく区切ることをお薦めします。そのほうが全期間を一度に処理するよりも都合よくいきます。たとえば、を1年間で検証したい場合、3か月ごとの4期間に分けるほうがよいと言えます。みなさんのパフォーマンス曲線が赤色でセクシーな女性のように表示されること、そのために本稿がヘッジャーのみなさんのすくなくともその結果の一部に役立つよう、またすくなくともみなさんがすばらしいヘッジ結果を出そうという気にさせることを願っています。最後にみなさんが本稿を楽しんでいただけますように!以下は私の仮想ヘッジパフォーマンスを記録した2分間ビデオです。(2007年03月19日~2007年04月19日)


MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/1493

添付されたファイル |
performance.mq4 (5.71 KB)
symbol-D1.mq4 (8.23 KB)
VirtualHedge.mq4 (24.81 KB)
初心者向け MQL4 言語テクニカルインディケータと組み込み関数 初心者向け MQL4 言語テクニカルインディケータと組み込み関数
本稿は『初心者向け MQL4 言語』シリーズの第3弾です。ここでは組み込み関数およびテクニカルインディケータと連携する関数の使い方を学習します。後者はご自身の Expert Advisor やインディケータをさらに発展させる上で基本となるものです。また、簡単な例で、市場参入のためのトレードシグナルの追跡法を見て、インディケータを正しく使用する方法が理解できるようにします。本稿が終わるころには、みなさんはこの言語自体について何か新しいおもしろいことを学んでいることでしょう。
トレーディングにおける数学:トレード結果の推定方法 トレーディングにおける数学:トレード結果の推定方法
「過去に得た利益は将来の成功を保証するものではない」ということを誰しも解っています。それでも、トレーディングシステムを推定することができるのは大事なことです。本稿ではトレード結果を推定するのに役立つ簡単で便利な方法を取り上げます。
インディケータ代替一目均衡表–設定, 用例 インディケータ代替一目均衡表–設定, 用例
代替一目均衡表を正しく設定するには?設定のパラメータ説明を読んでください。本稿は、インディケータ一目均衡表のみならず、パラメータ設定方法を理解するのに役立ちます。確実に、標準的な一目均衡表の設定方法についての理解も深まります。
検証の可視化:トレード履歴 検証の可視化:トレード履歴
本稿は、検証を可視化するとき、都合よくトレード履歴を閲覧する機能について説明します。