価格 Correlationの統計データを基にしたシグナルのフィルタリング

Михаил Тарачков | 29 10月, 2015


どのように始めるか

本稿執筆の考えが浮かんだのは、Larry Williams氏の著書 "Long-Term Secrets to Short-Term Trading"を読んだ後でした。その本には投資における世界記録保持者(1987年、氏はみずからの資本を100%増資しました。)が「大学教授や他の知識人は理論は豊かだが、マーケット知識に乏しい」というので過去の値動きと将来のトレンドの間に全く関係はないという神話を徹底的にはらいのけます。

コインと100回投げたら、50回は表、50回は裏です。投げ続けても表は50%、裏は50%です。確率は投げる間に変わることはありません。なぜならおのゲームは無作為で記憶することがないからです。マーケットがコインのように変動するとします。秩序のない変動です。

その結果、新規バーが現れるとき、価格は上下に関して同じ確率を持ち、前回バーは現在バーにまったく影響を与えることはありません。簡単です!トレーディングシステムを作り、ストップロスよりもテイクプロフィとを大きく設定します。(たとえばmath.を設定する。プラスゾーンへの期待)、そしてティックが行われます。ただ息をのむばかりです。ただし、問題はマーケットの変動に関するわれわれの予想は全く正しくないのです。率直に言えば、まったくおかしなものです。それを証明します。

MQL5 ウィザード を使って Expert Advisor のテンプレートを作成し、簡単なアルファベット数字を使用することでタスクを達成するのに適した条件にします。1、2、3本のバーが終了したあとに続く買いをシミュレートするようにExpert Advisor をエンコードします。シミュレーションはプログラムがただ分析されたバーのパラメータを覚えていることを意味します。この場合は注文送信(より便利な方法で)は動作しません。というのもスプレッドとスワップが情報受信の信頼性に疑問をもたらすためです。

以下がコードです。

//+------------------------------------------------------------------+
//|                                                     explorer.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//---Variables---
double profit_percent,open_cur,close_cur;
double profit_trades=0,loss_trades=0,day_cur,hour_cur,min_cur,count;
double open[],close[];
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
/* Calculate percent of closures with increase from the total number */
   profit_percent=NormalizeDouble(profit_trades*100/(profit_trades+loss_trades),2);
   Print("Percent of closures with increase ",profit_percent,"%");   // Enter data to the Journal
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---find out the time---
   MqlDateTime time;                        // Create a structure to store time
   TimeToStruct(TimeCurrent(),time);         // Structuring the data
   day_cur=time.day_of_week;              // Receive the value of the current day
   hour_cur=time.hour;                    // Receive the current hour
   min_cur=time.min;                      // Receive the current minute
//---Find out the prices---
   CopyOpen(NULL,0,0,4,open);ArraySetAsSeries(open,true);
   CopyClose(NULL,0,0,4,close);ArraySetAsSeries(close,true);

   if(close[1]<open[1]/*&&close[2]<open[2]&&close[3]<open[3]*/ && count==0) // If it closed with a loss
     {
      open_cur=open[0];                   // Remember open price of the current bar
      count=1;
     }
   if(open_cur!=open[0] && count==1)      // The current bar has closed
     {
      close_cur=close[1];                 // Remember the close price of the formed bar
      count=0;
      if(close_cur>=open_cur)profit_trades+=1;  // If the close price is higher than open,
      else loss_trades+=1;                      // +1 to closures with profit, otherwise +1 to closures with loss
     }
  }
//+------------------------------------------------------------------+

EUR/USDについて2000年1月1日~2010年12月31の期間で検証を行います。

図1 増加を伴う終了のパーセンテージ

図1 増加を伴う終了のパーセンテージ

(最初のコラムは全期間を、2番目~4番目は単一、二重、三重終了後を示しています。)(

これがお話した内容です!前回バーは現在バーにかなり大きな影響を与えます。それは価格が常に損失を取り戻そうとしているからです。


もう一歩前進

すばらしい!価格変動が偶然起こるのでないことがわかったら、すぐにこのすばらしい事実を利用すべきです。もちろん、自立したトレーディングシステムに対してだけでは不十分ですが、それは退屈でエラーのおこりがちなシグナルから解放してくれる優れたツールです。ではそれを実装しようではありませんか!

そこで必要なものです。

  1. 自立トレーディングシステム。少なくとも去年プラス結果を示したもの。
  2. 価格変動に関連があることを確認するよい例をいくつか。

L. Williams氏の著書に多くの有用な発想を見つけました。中の一つを共有します。

TDW(曜日)戦略です。これはある曜日に買いだけを行い、別の曜日にショートポジションだけをオープンするとどうなるのか確認するのを可能にします。 結果、一日内の価格は別の日よりもずっと大きな割合で成長すると仮定することができます。その理由は?地政学的な状況でしょうか、マクロ経済統計、または A. Elder氏の著書にあるように月曜と火曜 は素人の日、一方木曜と金曜は仕事をする日?それを解き明かします。

まず、毎日買いだけをして、その後売りだけをします。調査の終わりに最良の結果に匹敵することでしょう。これはトレーディングシステムのフィルターです。ところで、それについては少しお話があります。とてもありきたりなんですが!

システムはMAs および MACDakeの2つのシグナルを基にしています。                                                            

  1. 最初の移動平均が下から上へのゆっくりなものをクロスし、MACD ヒストグラムがゼロより下にあれば、それは買いです。
  2. 速い移動平均が上から下への速度の遅い移動平均をクロスし、MACD がゼロを上回ると売りです。 

ポイントからトレーリングストップを使ってポジションを終了します。ロトは - 0,1に固定されています。 

 やりやすいようにExpert Advisor クラスを別のヘッダファイルにいれました。

//+------------------------------------------------------------------+
//|                                                       moving.mqh |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| Класс my_expert                                                  |
//+------------------------------------------------------------------+
class my_expert
  {                                                  // Creating a class
   // Closed class members
private:
   int               ma_red_per,ma_yel_per;          // Periods of MAs
   int               ma_red_han,ma_yel_han,macd_han; // Handles
   double            sl,ts;                          // Stop orders
   double            lots;                           // Lot
   double            MA_RED[],MA_YEL[],MACD[];       // Arrays for the indicator values
   MqlTradeRequest   request;                         // Structure of a trade request
   MqlTradeResult    result;                          // Structure of a server response
                                                    // Open class members   
public:
   void              ma_expert();                                   // Constructor
   void get_lot(double lot){lots=lot;}                               // Receiving a lot  
   void get_periods(int red,int yel){ma_red_per=red;ma_yel_per=yel;} // Receiving the periods of MAs
   void get_stops(double SL,double TS){sl=SL;ts=TS;}                  // Receiving the values of stops
   void              init();                                         // Receiving the indicator values
   bool              check_for_buy();                                // Checking for buy
   bool              check_for_sell();                               // Checking for sell
   void              open_buy();                                     // Open buy
   void              open_sell();                                    // Open sell
   void              position_modify();                              // Position modification
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
/* Function definition */
//---Constructor---
void my_expert::ma_expert(void)
  {
//--- Reset the values of variables
   ZeroMemory(ma_red_han);
   ZeroMemory(ma_yel_han);
   ZeroMemory(macd_han);
  }
//---The function for receiving the indicator values---
void  my_expert::init(void)
  {
   ma_red_han=iMA(_Symbol,_Period,ma_red_per,0,MODE_EMA,PRICE_CLOSE); // Handle of the slow MA
   ma_yel_han=iMA(_Symbol,_Period,ma_yel_per,0,MODE_EMA,PRICE_CLOSE); // Handle of the fast MA
   macd_han=iMACD(_Symbol,_Period,12,26,9,PRICE_CLOSE);               // Handle of MACDaka
//---Copy data into arrays and set indexing like in a time-series---
   CopyBuffer(ma_red_han,0,0,4,MA_RED);
   CopyBuffer(ma_yel_han,0,0,4,MA_YEL);
   CopyBuffer(macd_han,0,0,2,MACD);
   ArraySetAsSeries(MA_RED,true);
   ArraySetAsSeries(MA_YEL,true);
   ArraySetAsSeries(MACD,true);
  }
//---Function to check conditions to open buy---   
bool my_expert::check_for_buy(void)
  {
   init();  //Receive values of indicator buffers
/* If the fast MA has crossed the slow MA from bottom up between 2nd and 3rd bars, 
   and there was no crossing back. MACD-hist is below zero */
   if(MA_RED[3]>MA_YEL[3] && MA_RED[1]<MA_YEL[1] && MA_RED[0]<MA_YEL[0] && MACD[1]<0)
     {
      return(true);
     }
   return(false);
  }
//----Function to check conditions to open sell---
bool my_expert::check_for_sell(void)
  {
   init();  //Receive values of indicator buffers
/* If the fast MA has crossed the slow MA from up downwards between 2nd and 3rd bars,
  そしてクロスバックcrossing backはありません。MACD-hist is above zero */
   if(MA_RED[3]<MA_YEL[3] && MA_RED[1]>MA_YEL[1] && MA_RED[0]>MA_YEL[0] && MACD[1]>0)
     {
      return(true);
     }
   return(false);
  }
//---Open buy---
/* Form a standard trade request to buy */
void my_expert::open_buy(void)
  {
   request.action=TRADE_ACTION_DEAL;
   request.symbol=_Symbol;
   request.volume=lots;
   request.price=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
   request.sl=request.price-sl*_Point;
   request.tp=0;
   request.deviation=10;
   request.type=ORDER_TYPE_BUY;
   request.type_filling=ORDER_FILLING_FOK;
   OrderSend(request,result);
   return;
  }
//---Open sell---
/* Form a standard trade request to sell */
void my_expert::open_sell(void)
  {
   request.action=TRADE_ACTION_DEAL;
   request.symbol=_Symbol;
   request.volume=lots;
   request.price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
   request.sl=request.price+sl*_Point;
   request.tp=0;
   request.deviation=10;
   request.type=ORDER_TYPE_SELL;
   request.type_filling=ORDER_FILLING_FOK;
   OrderSend(request,result);
   return;
  }
//---Position modification---
void my_expert::position_modify(void)
  {
   if(PositionGetSymbol(0)==_Symbol)
     {     //If a position is for our symbol
      request.action=TRADE_ACTION_SLTP;
      request.symbol=_Symbol;
      request.deviation=10;
      //---If a buy position---
      if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
        {
/* if distance from price to stop loss is more than trailing stop
   and the new stop loss is not less than the previous one */
         if(SymbolInfoDouble(Symbol(),SYMBOL_BID)-PositionGetDouble(POSITION_SL)>_Point*ts)
           {
            if(PositionGetDouble(POSITION_SL)<SymbolInfoDouble(Symbol(),SYMBOL_BID)-_Point*ts)
              {
               request.sl=SymbolInfoDouble(Symbol(),SYMBOL_BID)-_Point*ts;
               request.tp=PositionGetDouble(POSITION_TP);
               OrderSend(request,result);
              }
           }
        }
      //---If it is a sell position---                
      else if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
        {
/*  if distance from price to stop loss is more than the trailing stop value
   and the new stop loss is not above the previous one. Or the stop loss from the moment of opening is equal to zero */
         if((PositionGetDouble(POSITION_SL)-SymbolInfoDouble(Symbol(),SYMBOL_ASK))>(_Point*ts))
           {
            if((PositionGetDouble(POSITION_SL)>(SymbolInfoDouble(Symbol(),SYMBOL_ASK)+_Point*ts)) || 
               (PositionGetDouble(POSITION_SL)==0))
              {
               request.sl=SymbolInfoDouble(Symbol(),SYMBOL_ASK)+_Point*ts;
               request.tp=PositionGetDouble(POSITION_TP);
               OrderSend(request,result);
              }
           }
        }
     }
  }
//+------------------------------------------------------------------

「MQL5のオブジェクト指向方法 を使用した Expert Advisor のプログラミング」の著者に対する控えめな敬意です。それなしで何をしようというのでしょう!この悪を熟知していない方はこの記事を一読されることをお薦めしますが、極端に機能的なオブジェクト指向プログラミングです。

クラスによtファイルをExpert Advisorのメインコードに追加?オブジェクトを作成し、関数を初期化します。

//+------------------------------------------------------------------+
//|                                                       Moving.mq5 |
//|                        Copyright 2011, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//---Include a file with the class---
#include <moving.mqh>
//---External Variables---
input int MA_RED_PERIOD=7; // The period of a slow MA
input int MA_YEL_PERIOD=2; // The period of a fast MA
input int STOP_LOSS=800;   // Stop loss
input int TRAL_STOP=800;   // Trailing stop
input double LOTS=0.1;     // Lot
//---Create an object---
my_expert expert;
//---Initialize the MqlDataTime structure---
MqlDateTime time;
int day_of_week;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---Initialize the EA
   expert.get_periods(MA_RED_PERIOD,MA_YEL_PERIOD);   // Set the MA periods
   expert.get_lot(LOTS);                              // Set the lot
   expert.get_stops(STOP_LOSS,TRAL_STOP);             // Set stop orders  
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   TimeToStruct(TimeCurrent(),time);
   day_of_week=time.day_of_week;
   if(PositionsTotal()<1)
     {
      if(day_of_week==5 && expert.check_for_buy()==true){expert.open_buy();}
      else if(day_of_week==1 && expert.check_for_sell()==true){expert.open_sell();}
     }
   else expert.position_modify();
  }
//+------------------------------------------------------------------+

できました!特別な機能を記録します。ソフトウェアレベルで曜日を特定するには、私は MqlDateTime ストラクチャを使いました。まず、現在のサーバー時刻をストラクチャ化されたフォーマットに変換します。現在曜日のインデックス(1-月曜、~5-金曜)を取得し、それを設定した値と比較します。

やってみてください!煩雑な調査と余分なディジット余計な数字で負荷を増やさないために、結果をすべて表にまとめています。

それがこちらです。 

表1 毎日「買い」の概要

表1 毎日「買い」の概要

表2 毎日「売り」の概要

表2 毎日「売り」の概要

一番良い結果はグリーンで強調表示しています。一番悪いものはオレンジです。

前述の処理のあと、システムが安値に関連するドローダウン、勝利トレードのよいパーセンテージ(ここでより少ない トレード はより良い)、比較的高収益のトレードの組合せで収益を確保するように予約をします。

あきらかにもっとも効果的なシステムは金曜日に買い、月曜日に売るというものです。これら条件を組み合わせます。

if(PositionsTotal()<1){
      if(day_of_week==5&&expert.check_for_buy()==true){expert.open_buy();}
      else if(day_of_week==1&&expert.check_for_sell()==true){expert.open_sell();}}
   else expert.position_modify();

これでExpert Advisor は双方向にポジションをオープンしますが厳格に決められた日に行います。フィルターなし、またありで取得された図を描きます。

図2 フィルターなしのEA 検証結果(EURUSD, H1, 01.01.2010-31.12.2010,)

図2 フィルターなしのEA 検証結果(EURUSD, H1, 01.01.2010-31.12.2010,)

図3 フィルターありのEA 検証結果 (EURUSD, H1, 01.01.2010-31.12.2010,)

図3 フィルターありのEA 検証結果 (EURUSD, H1, 01.01.2010-31.12.2010)

結果はお気に召しましたか?フィルターを使うことでトレーディングシステムはより安定します。変更前、Expert Advisor は主に検証期間前半で残高を増やし、「アップデート」後、全期間を通して残高を増やします。

レポート比較を行います。

表3 フィルター使用前後の検証結果

表3 フィルター使用前後の検証結果

唯一悲惨な要因、それは無視できないものですが、は約 1000 米ドル (26%)純収益が下がっていることです。ただし、トレード数を3.5倍減らしました。それはまずマイナストレードになる可能性、次にスプレッドの出費 (218*2-62*2=312 米ドル でその対象はaEUR/USDです。)を減らします。勝利パーセンテージ57%に増加し、それはすでに大きな増加です。一方でトレード毎の収益は14% 、113 米ドル増えます。As L. Williams 氏はこうおっしゃるでしょう。「これはトレーディングの価値がある金額だ!」


おわりに

価格は無作為に変動しません。これは事実です。この事実は利用可能で、利用しないテはありません。私は例を一つ提供しただけです。それは数知れない多様な中のほんの一部で、トレーディングシステムのパフォーマンスを向上させることのできる技術です。ただし、この多様性には悪が潜んでいます。フィルターがすべて必ずしも統合できるわけではありません。よって選ぶときはあらゆる場合を想定して慎重に選択する必要があります。

フィルターがどんなに完璧でも、フィルターは収益性あるトレードを削除することもあることを忘れないでください。 すなわちあなたの収益です。ご健闘をお祈りします!