モスクワ為替先物のスプレッド戦略の開発例

MetaQuotes | 13 2月, 2017

MT5 プラットフォームでは、同時に複数の金融商品のトレードロボットをテストすることができます。組み込みのストラテジーテスターは、開発者が手動で行う必要がないように、ブローカーのサーバーからヒストリーデータを自動的にダウンロードします。シンプルかつ確実に異なるシンボルのミリ秒単位のティックによるトレード環境を再現することが可能です。この記事では、2つのモスクワ先物でスプレッドストラテジーのテストと開発をします。


資産の負の相関: Si と RTS

Si-M.Y と RTS-M.Y 先物は、モスクワの取引所でトレードされています。先物の種類はしっかりと関連付けられます。M.Yは、有効期限を意味します。

Siは、米ドル/ロシアルーブルの為替レートで、RTSは米ドルで表されます。RTS指数にはロシア企業の株式が含まれています。この株式はルーブル単位です。USD/RURの変動も影響を与えます。価格チャートは、片側が成長するともう片方が下落します。


可視性を上げるため、これらのチャートに標準偏差チャネルを導入しました。


Si と RTS の線形回帰を計算します。

線形回帰式 Y(X)= A (X) + B を使用して、2つの相関を表現することができます 。CalcShowRegression_script.mq5のスクリプトを作成しましょう。これは、終値に二つの配列を取り、係数を計算し、チャートにまっすぐなラインを描写します。

ALGLIB関数を使用して、回帰係数が計算され、標準ライブラリのグラフィック クラスで描画されます。



Siと合成系の広がりをインジケーターで描画

線形回帰の係数が分かり、Y(RTS) = A*RTS+B のチャートを描写することができます。ソースアセットと合成シーケンスの差を「スプレッド」と呼びましょう。この差は、各足で負から正になります。

視覚化するために、TwoSymbolsSpread_Ind.mql5インジケーターを作成しましょう。正の値が青で描かれ、負値は黄色になります。

このインジケーターは、新しい足ができたとき、EAジャーナル線形回帰係数に書き込みます。また、SiとRTSを含む新しいローソク足が開かれるまで待機します。このようにこのインジケーターは、正確さと計算の精度を保証します。


最新100本の足のスプレッドチャネルの線形回帰を作成します。

スプレッドインジケーターは、 Si と合成シンボルの変更の差を示します。現在のスプレッドを評価するため、SpreadRegression_Ind.mq5インジケーターを作成しましょう。ラインパラメータは、線形回帰を使用して計算されます。デバッグ用にグラフに 2 つのインジケーターを起動しましょう。

最新の100本の足のスプレッドの値に応じて、赤いトレンド ラインが変化します。必要なデータの最小があり、トレードシステムを構築することができます。


戦略#1: 線形回帰斜面をスプレッドチャートに変更します。

TwoSymbolsSpread_Ind.mql5インジケーターでのスプレッドの値は Si と Y (RTS) の差として計算されます。Y(RTS)=A*RTS + B。デバッグモード (F5 キー) でインジケーターを実行することによって、シンプルに確認できます。


線形回帰スプレッドチャートに添付のトレンドの変化を監視するシンプルなEAを作成してみましょう。ラインのトレンドは方程式の係数: Y=A*X+B。スプレッドチャートでトレンドが正のとき、A > 0。トレンドが負の場合、A < 0。線形回帰は、スプレッドチャートの最後の 100本 の値を使用して計算されます。Strategy1_AngleChange_EA.mq5.がEAの一部です。

#include <Trade\Trade.mqh>
//+------------------------------------------------------------------+
//| Spread strategy type                                             |
//+------------------------------------------------------------------+
enum SPREAD_STRATEGY
  {
   BUY_AND_SELL_ON_UP,  //1st で買い、2 nd で売り
   SELL_AND_BUY_ON_UP,  //1で売り、2で買い
  };
//---
input int       LR_length=100;                     //スプレッドの回帰のバーの数
input int       Spread_length=500;                 //スプレッドのバーの数
input ENUM_TIMEFRAMES  period=PERIOD_M5;           //時間枠
input string    symbol1="Si-12.16";                //ペアの最初のシンボル
input string    symbol2="RTS-12.16";               //ペアの 2 番目のシンボル
input double    profit_percent=10;                 //ロックする利益のパーセント
input SPREAD_STRATEGY strategy=SELL_AND_BUY_ON_UP; //スプレッドストラテジーのタイプ
//---インジケーター ハンドル
int ind_spreadLR、ind、ind_2_symbols;
//---トレードオペレーションのクラス
CTrade trade;
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//スプレッドチャート(X、Y) の線形回帰斜面係数---Y(X)=A*X+B
   static double Spread_A_prev=0;
   if(isNewBar())
      PrintFormat("New bar %s opened at %s",_Symbol,TimeToString(TimeCurrent(),TIME_DATE|TIME_SECONDS));
//---インジケーターのデータを更新するための 2 つのシンボルを待機
   if(BarsCalculated(ind_spreadLR)==Bars(_Symbol,_Period))
     {
      //---1、2 (「昨日」と「一昨日」) のインデックスを持つバー用のスプレッドチャートで線形回帰値を取得
      double LRvalues[];
      double Spread_A_curr;
      int copied=CopyBuffer(ind_spreadLR,1,1,2,LRvalues);
      if(copied!=-1)
        {
         //---最後に形成された足の線形回帰係数完了 (「昨日」) バー
         Spread_A_curr=LRvalues[1]-LRvalues[0];
         //---線形回帰斜面が変わった場合
         if(Spread_A_curr*Spread_A_prev<0)
           {
            PrintFormat("Slope of LR changed, Spread_A_curr=%.2f, Spread_A_prev=%.2f: %s",
                        Spread_A_curr,Spread_A_prev,TimeToString(TimeCurrent(),TIME_SECONDS));
            //---両方のシンボルで相場にオープンポジションがない場合
            if(PositionsTotal()==0)
               DoTrades(Spread_A_curr-Spread_A_prev>0,strategy,symbol1,1,symbol2,1);
            //---オープン ポジションがある場合は逆に
            else
               ReverseTrades(symbol1,symbol2);
           }
         //---LR 斜面は変わっていません。浮動利益を確認します。 ポジションを閉じるまでの時間はあるでしょうか
         else
           {
            double profit=AccountInfoDouble(ACCOUNT_PROFIT);
            double balance=AccountInfoDouble(ACCOUNT_BALANCE);
            if(profit/balance*100>=profit_percent)
              {
               //---必要な浮動利益レベルに達した
               trade.PositionClose(symbol1);
               trade.PositionClose(symbol2);
              }
           }
         //---新しい足の始値で比較するトレンドの方向を記録
         Spread_A_prev=Spread_A_curr;
        }
     }
  }

トレンドが変化するときに、仮定を排除するために、トレードルールを逆転させることができる外部パラメータを追加しましょう。

input SPREAD_STRATEGY strategy=SELL_AND_BUY_ON_UP; //スプレッド戦略のタイプ

これで、EAのテストとデバッグを開始できます。


トレード戦略 #1 のテスト

ビジュアル テスト モードがデバッグに最適です。ツール-設定-デバッグ メニューを使用して、必要なデータを設定します。

  1. シンボル
  2. 時間枠
  3. テスト間隔
  4. 実行
  5. デポジット
  6. ティック生成モード

推奨モードは「リアルティックに基づく全ティック」です。ここで、EAは記録されたヒストリーデータを使用してテストされ、実際のトレード条件に近い結果になります。

MT5 トレード サーバーは自動的にヒストリーデータを収集し、すべてのティックを保存し、最初のリクエスト時にターミナルに全体のティック履歴を送信します。

このデバッグ モードでは、必要に応じてブレークポイントを使用して、任意の変数の値を確認しながらビジュアル モードでテストのプロセスを実行することができます。ロボットで使用されるインジケーターは、グラフに自動的に読み込まれますが、裁量で添付する必要はありません。

EAのコードをデバッグすると、パラメータを最適化できます。


トレード戦略 #1 の最適化

Strategy1_AngleChange_EA.mq5EAは、(黄色で強調) の最適化によって構成することができる外部パラメータを持ちます。

input int       LR_length=100;                     //スプレッドの回帰のバーの数
input int       Spread_length=500;                 //スプレッドの計算の足の数
input double    profit_percent=10;                 //ロックする利益のパーセント

input SPREAD_STRATEGY strategy=SELL_AND_BUY_ON_UP; //スプレッドストラテジーのタイプ

差があるかどうかを理解するためにprofit_percentの2つのバージョンを最適化します。つまり、ストラテジーのパラメータの値を修正し、profit_percentに基づいて、 0.2 から 3.0%まで、2つのメソッドの全体像を見るために最適化します。

BUY_AND_SELL_ON_UP のルールのラインのトレンドが正、負の最適化から変更されたとき良い結果は表示されません。一般に、この相場が魅力的な見ていない、 2 ヶ月のテスト中に多くの損失が発生しています。


SELL_AND_BUY_ON_UP ルールは、良い最適化結果になっています。15つ中5つのテストの実行でプラスになっています。


2016年8月1日から2016年9月30 日 (2 ヶ月間)のヒストリーデータの最適化。一般的に、トレードは両方とも有望ではありません。おそらく、問題はエントリーに使用しているパラメータの問題です。つまり、過去100本のトレンドラインの勾配です。2番目のバージョンを開発してみましょう。


戦略#2: 確定足でのスプレッドサイン

2番目のストラテジーでは、スプレッドサインの変化を分析します。確定足の値のみ分析します。すなわち、「今日」の始値をチェックします。「一昨日」のバーの普及は負で、"昨日"の足は正でした。スプレッドが上がったことがわかります。このコードは、トレードの任意の方向で広がる可能性があります。戦略パラメータを使用してエントリー方向を変更できます。Strategy2_SpreadSignChange_EA.mq5コードのブロックです。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---Symbol1 と Y(Symbol2)=A*Symbol2+B の差が前のスプレッド値です。
   static double Spread_prev=0;
   if(isNewBar())
      PrintFormat("New bar %s opened at %s",_Symbol,TimeToString(TimeCurrent(),TIME_DATE|TIME_SECONDS));
//---インジケーターのデータを更新するための 2 つのシンボルを待機
   if(BarsCalculated(ind_spreadLR)==Bars(_Symbol,_Period))
     {
      //---インデックス1と2のスプレッドの値を取得
      double SpreadValues[];
      int copied=CopyBuffer(ind_spreadLR,0,1,2,SpreadValues);
      double Spread_curr=SpreadValues[1];
      if(copied!=-1)
        {
         //---スプレッドサインが変わった場合、現在と以前の値の積は0未満です
         if(Spread_curr*Spread_prev<0)
           {
            PrintFormat("Spread sign changed, Spread_curr=%.2f, Spread_prev=%.2f: %s",
                        Spread_curr,Spread_prev,TimeToString(TimeCurrent(),TIME_SECONDS));
            //---両方のシンボルでオープン ポジションがない場合、
            if(PositionsTotal()==0)
               DoTrades(Spread_curr>0,strategy,symbol1,1,symbol2,1);
            //---オープン ポジションがある場合、逆
            else
               ReverseTrades(symbol1,symbol2);
           }
         //---スプレッドサインが変わっていない場合、浮動利益を確認します。決済する時間でしょうか
         else
           {
            double profit=AccountInfoDouble(ACCOUNT_PROFIT);
            double balance=AccountInfoDouble(ACCOUNT_BALANCE);
            if(profit/balance*100>=profit_percent)
              {
               //---利益を取る必要なレベルに達した
               trade.PositionClose(symbol1);
               trade.PositionClose(symbol2);
              }
           }
         //---新しい足の始値でスプレッドを比較する
         Spread_prev=Spread_curr;
        }
     }
  }

まず、ビジュアル テスト モードで EA をデバッグし、 profit_percentの最初の戦略のようにして最適化を実行します。結果:



ご覧の通り、2番目の戦略に適用される「最初に売り、2番目に買い」は、期待はずれのテスト結果でした。「最初に買い、2番目に売り」は、すべてテストでより多くの損失になります。

3番目の戦略を作成してみましょう。


戦略#3: 現在の足のスプレッドサインの変更とN ティックを確認

前の2つのストラテジーは、始値でだけ稼働します。つまり、足が確定する瞬間にだけ分析されます。現在の足内で動くようにしましょう。ティックごとにスプレッドの変動を分析してみましょう。確定足のスプレッドが現在足と異なったら、スプレッドの方向が変わったとみなしましょう。

また、スプレッドサインの変化は、直近のNティックは安定的な方が良いです。これは、ダマシのフィルターとして必要です。外部パラメータ ticks_for_trade=10 を追加する必要があります。直近10ティックでスプレッドサインが負の場合、かつ、前の足が正の場合、EAはエントリーします。Strategy3_SpreadSignOnTick_EA.mq5のEAの OnTick() 関数です。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(isNewBar())
      PrintFormat("New bar %s opened at %s",_Symbol,TimeToString(TimeCurrent(),TIME_DATE|TIME_SECONDS));
//---インジケーターのデータを更新するための 2 つのシンボルを待機
   if(BarsCalculated(ind_spreadLR)==Bars(_Symbol,_Period))
     {
      //---現在の (今日) と (昨日) に前のバーでスプレッドを取得
      double SpreadValues[];
      int copied=CopyBuffer(ind_spreadLR,0,0,2,SpreadValues);
      double Spread_curr=SpreadValues[1]; //現在の形成中の足のスプレッド
      double Spread_prev=SpreadValues[0]; //前の確定足のスプレッド
      if(copied!=-1)
        {
         //---スプレッドサインの変化はが最後の ticks_for_tradeで安定している場合
         if(SpreadSignChanged(Spread_curr,Spread_prev,ticks_for_trade))
           {
            PrintFormat("Spread sign changed, Spread_curr=%.2f, Spread_prev=%.2f: %s",
                        Spread_curr,Spread_prev,TimeToString(TimeCurrent(),TIME_SECONDS));
            //---両方のシンボルの最後の ticks_for_trade トレード値
            ShowLastTicksComment(ticks_for_trade);
            //---両方のシンボルでオープン ポジションがない場合、
            if(PositionsTotal()==0)
               DoTrades(Spread_curr>0,strategy,symbol1,1,symbol2,1);
            //---オープン ポジションがある場合、逆
            else
               ReverseTrades(Spread_curr>0,positionstype,symbol1,symbol2);
           }
         //---スプレッドサインが変わっていない場合、浮動利益を確認 - 決済の時期でしょうか。
         else
           {
            double profit=AccountInfoDouble(ACCOUNT_PROFIT);
            double balance=AccountInfoDouble(ACCOUNT_BALANCE);
            if(profit/balance*100>=profit_percent)
              {
               //---浮動利益レベルに達した、
               trade.PositionClose(symbol1);
               trade.PositionClose(symbol2);
               positionstype=0;
              }
           }
        }
     }
   }

このEAでシグナルが表示され、両方のシンボルの最後の N のティックの値をグラフに表示する ShowLastTicksComment() 関数を追加しました。視覚的なミリ秒単位の精度で、ストラテジーとティック変化をテストできます。

最初の 2 つの戦略の適用を開始し、次の結果を受信します。

「最初に買い、次に売る」


「最初に売り、次に買う」


このようなシンプルな最適化の結果は、大幅な改善ではありません。


戦略4: スプレッドがプリセットのパーセント値に達した

4番目にスプレッドトレードの最後の戦略を作成します。上の3つのメソッドと同じくらいシンプルです。トレードシグナルは、スプレッドが特定のパーセントに達したときに表れます。 spread_delta。ハンドラ OnInit() がわずかに変更され、Strategy4_SpreadDeltaPercent_EA.mq5のようになります。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(isNewBar())
      PrintFormat("New bar %s opened at %s",_Symbol,TimeToString(TimeCurrent(),TIME_DATE|TIME_SECONDS));
//---インジケーターのデータを更新するための 2 つのシンボルを待機
   if(BarsCalculated(ind_spreadLR)==Bars(_Symbol,_Period))
     {
      //---現在 (今日) バーのスプレッドの値を得る
      double SpreadValues[];
      int copied=CopyBuffer(ind_spreadLR,0,0,1,SpreadValues);
      double Spread_curr=SpreadValues[0]; //現在の形成中の足のスプレッド
      if(copied!=-1)
        {
         MqlTick tick;
         SymbolInfoTick(symbol1,tick);
         double last=tick.last;
         double spread_percent=Spread_curr/last*100;
         //---スプレッドがspread_delta 値に到達した場合
         if(MathAbs(spread_percent)>=spread_delta)
           {
            PrintFormat("Spread reached %.1f%% (%G) %s",
                        spread_percent,TimeToString(TimeCurrent(),TIME_SECONDS),
                        Spread_curr);
            //---両方のシンボルでオープン ポジションがない場合、
            if(PositionsTotal()==0)
               DoTrades(Spread_curr,strategy,symbol1,1,symbol2,1);
            //---オープン ポジションがある場合、逆
            else
               ReverseTrades(Spread_curr,positionstype,symbol1,symbol2);
           }
         //---スプレッドは許容範囲、変動利益を確認 - 決済しますか
         else
           {
            double profit=AccountInfoDouble(ACCOUNT_PROFIT);
            double balance=AccountInfoDouble(ACCOUNT_BALANCE);
            if(profit/balance*100>=profit_percent)
              {
               //---必要な浮動利益レベルに達した、
               trade.PositionClose(symbol1);
               trade.PositionClose(symbol2);
               positionstype=0;
              }
           }
        }
     }
  }

スプレッドがprofit_percent= 2 に達した場合、ポジションは決済されます。今回は固定値です。0.1 〜 1% の範囲でspread_deltaパラメータを使用して最適化を開始します。

「最初に買い、次に売る」


「最初に売り、次に買う」


今回、「最初に買い、次に売る」ルールは 2番目のルールより良く見えます。また、その他のパラメータを使用してさらに最適化できます。


MT5-トレーディング戦略の開発環境

この記事では、スプレッドトレードの 4つ のシンプルな戦略を検討しました。これらのストラテジーから生成されたテスト結果や最適化結果は、実際にトレードするための指針ではありません。これはある程度ランダムでありえるからです。この記事の当初の意図は、MT5でデバッグすることがいかに簡単で便利か示すためのものです。

MT5テスターは、自動トレードシステムの開発者にとって便利な特徴があります。

この記事で、ストラテジーテスターは正しい方向性を見つける研究ツールとして使用されました。定性的な結論をすることが 1 つのパラメータを使用して、最適化の一環として行われました。新しいルールを追加し、既存のものを変更し、完全な EAの最適化を実行できます。計算をスピードアップするには、MT5 プラットフォーム、特別設計のMQL5 クラウド ネットワークを使用します。


戦略上重要な注意事項

通常、拡散計算についてシンボルの検索には、値の増分が絶対値の代わりに使用されます。Delta[i]=Close[i]-Close[i-1] が、Close[i]の代わりに計算されます。

バランスの取れたトレードをするため、各シンボルごとにボリュームを選択してください。この記事では、各シンボルごとに 1 ロットを使用しました。

Si と RTS のコントラクトの現在の設定は、テスト中に使用されます。次のことが強く言えるでしょう。

インデックス計算の情報は、 http://fs.moex.com/files/4856のMOEX サイトで確認できます。したがって、ストラテジーテスターの結果はそのときのドルに依存しています。この記事には、2016 年 10 月 25 日の最適化結果のスクリーン ショットがあります。

このコードは、最適なパフォーマンスの条件下で実行されます。つまり、他の結果を送るオーダーのハンドルを含んでいません。

先物の流動性とグラフは、有効期限の終わりに改善されます。このコードでは、1 つのシンボルの引用符を受信すると、2 番目のシンボル (トレード所に何らかの理由でない) に全体のバーを逃したと、状況の明示的な処理は含まれません。しかし、インジケーター、EA の使用のスプレッドの値を計算するため、両方のシンボルのバーの同期を待機し、イベントを書き込みます。

この記事ではスプレッド、平均値から偏差の統計の分析がないため、より信頼性の高いトレードルールを作成するために必要です。

オーダー ブックはMT5 ストラテジーテスターでシミュレートされたものではありませんので、相場の板の分析は使用されません。

注意:この記事で動的に使用されるインジケーターは、スプレッドチャート、トレンド ラインを作成するための線形回帰係数を再計算します。したがって、テストの終わりに、チャートとインジケーターの値の外観は、テスト プロセス中に表示されたもの異なることがあります。

インジケーターや EA はリアルタイムでプロセスを表示するビジュアル テスト モードで下記を実行します。


関連記事:


この記事で使用されているプログラム:

#
 名前
タイプ
詳細
1
CalcShowRegression_script.mq5
スクリプト
線形回帰係数を計算して (СGraphic クラスと Alglib 関数を使用して) トレンド ラインとポイント グラフを描画
2
TwoSymbolsSpread_Ind.mql5
インジケーター
インジケーター 2 つのシンボルの広がりヒストグラムを描画します
3
SpreadRegression_Ind.mq5
インジケーター インジケーターは、をスプレッドチャートと回帰直線を描画します。
4
Strategy1_AngleChange_EA.mq5
EA
戦略 #1. 方程式Y=A*X+Bの線形回帰係数の符号の変化に基づくトレード始値のタイミングにのみエントリ
5
Strategy2_SpreadSignChange_EA.mq5 EA 戦略 #2. スプレッド値の符号の変化に基づくトレード始値のタイミングにのみエントリ
6
Strategy3_SpreadSignOnTick_EA.mq5
EA
戦略 #3。スプレッド値の符号の変化に基づくトレード現在の足内でのエントリは、符号の変化は最後 N ティックの間が安定している必要があります。
7 Strategy4_SpreadDeltaPercent_EA.mq5 
EA
戦略 #4。トレードは、スプレッドの特定のパーセント値に達する方法に基づいています。最初に受信したティック内での分析とエントリー