English Русский 中文 Español Deutsch Português
preview
MetaTrader 5におけるバイナリーオプション戦略のテストと最適化

MetaTrader 5におけるバイナリーオプション戦略のテストと最適化

MetaTrader 5テスター | 3 4月 2023, 10:47
842 0
Roman Poshtar
Roman Poshtar

はじめに

最近、バイナリーオプションに興味を持ちました。ネットサーフィンをして証券会社を調べると、ほとんどの人がその証券会社のプラットフォームを使って取引していることがわかりました。これらのプラットフォームは、戦略をテストする機能を持たず、せいぜい標準的な指標の貧弱なセットしか持っていません。バイナリーオプションの様々な戦略を大量に検討した結果、、これらの戦略やその最適化をどのように確認するのかが気になり始めました。いつものように、愛するMetaTrader 5が私を救ってくれました。そして、いつものように、複雑な数式やコードを使わずに、できるだけシンプルに私の実験を皆さんにお伝えしようと思います。ただしその前に、バイナリーオプションを掘り下げる価値があるのかどうか、少し理論や論拠を説明します。


理論

バイナリーオプションは、選択した期間内の資産価格の方向性を予測することを主題とするデジタル契約です。課題は、市場状況の展開について、資産が上昇するか下落するかという2つのシナリオのうち、どちらかを正しく判断することです。現在では、通貨、証券、コモディティのオンラインオプションが豊富に揃っています。天気予報を含め、あらゆるものが資産になり得ます。取引には、巨額の投資や市場交換プロセスの分野における深い金融・経済知識は必要ありません。


バイナリーオプションの種類

ラダーオプションはバイナリオプションの最も単純なタイプで、トレーダーは価格がどの方向に行くかを予想しなければならなないだけです。強気なトレンドでは、ハイ(Call)を買うことが望ましいです。一方、ロー (Put) は、資産の下降が予想される場合に購入します。ラダーオプションの利益は、ベット額の10%から80%まで様々です。

ワンタッチオプションは合意を表し、希望する価格レベルが達成されるかどうかを予測することが必要です。決済中のクウォートの場所は関係ありません。所定レベルのタッチで十分です。ワンタッチオプションの収益性は通常より高く、95%に達することもありますが、ほとんどの場合、予測することは非常に難しいので、100%すべてを失うこともあります。

レンジオプションでは、期限が切れる時に資産の価値が位置する価格帯を予測します。また、このオプションの理解や予測は困難です。収益性は最大95%です。

以下では、私が考える最も人気のあるラダーオプションの戦略をテストし、最適化します。


長所と短所

長所

  • シンプル:損失や利益の可能性がある金額を固定することで、ストップロスやテイクプロフィットレベルの複雑な計算をする必要がなく、初心者の方には特に便利です。
  • オプション証券会社のWebサイトから簡単な登録をおこなうだけで、書類一式は不要です。
  • 企業株、株価指数、原油、金、暗号通貨など、さまざまなリソースがあり、初期資金は100ドル以下から始めることができます。株式や先物の取引には、より多額の初期入金が必要です。

短所

  • 高いリスクとマイナスの期待:1回負けると、取り戻すのに2つの勝ちが必要です。採算効率は最大80%です。損失を伴う操作は、利益を伴う操作よりもコストがかかります。
  • 「カジノ」モードは、長い目で見ると損失をもたらします。取引時にカジノのトリックを適用しようとしたり、マーチンゲールなどの平均法もありますが、これは正しい取引のルールに違反し、最終的に預金を破棄することになります。
  • 手数料が高くなります。

    通貨ペア:最適化とフォワードテスト範囲、設定

    以下は、最適化およびテストのすべてのパラメータです。

    • 外為
    • EURUSD
    • M5、M15、M30、H1
    • 有効期限:5分、15分、30分、1時間
    • 最適化範囲:1年(2021.01.28 - 2022.01.28
    • フォワードテスト範囲:1年(2022.01.28 - 2023.01.28)
    • 初期入金:10,000円
    • レート:10
    • 金利:80%

      技術的な側面

      テストと最適化のための入力が必要です。

      1. StartDepo:初期入金
      2. OptionRate:レート
      3. ExpirationTime:有効期限
      4. ProfitPercent:収益性の割合
      5. TimeFrame:指標の時間枠
      6. Optimization:最適化スイッチ
      7. OptimizationFileName:最適化結果を保存するためのファイル名
      input string N0 = "------------Open settings----------------";
      input double StartDepo = 10000;
      input int OptionRate = 10;
      input string N1 = "------------Close settings---------------";
      input int ExpirationTime = 1; //ExpirationTime 1=5 min, 2=15 min, 3=30 min, 4=60 min
      input double ProfitPercent = 80;
      input string N2 = "------------Optimization settings--------";
      input int TimeFrame = 1; //TimeFrame 1=5 min, 2=15 min, 3=30 min, 4=60 min
      input bool Optimization = false;
      input string OptimizationFileName = "Optimization.csv";
      input string N3 = "------------Other settings---------------";
      input int Slippage = 10;
      input int Magic = 111111;
      input string EAComment = "2Ma+RSI+Stochastic Oscillator";

      また、保証金の変化や、収益性の高いオプション購入数と収益性の低いオプション購入数の変化を保存・追跡するための変数も必要になります。

      1. XStartDepo:現在の預金を保存
      2. Profit:オプションの購入で利益を得た回数を保存
      3. Loss:採算の取れないオプションの数を保存
      double XStartDepo = StartDepo;
      int Profit=0;
      int Loss=0;

      MetaTrader 5 でポジションの開始時刻を追跡し、有効期限の後にポジションを決済するには、ポジションの開始時刻を返す関数を使用することになります。

      //+------------------------------------------------------------------+
      //| Get open time in positions                                       |
      //+------------------------------------------------------------------+
      datetime GetTime(string symb="0", int type=-1, int mg=-1,int index=0) {
       datetime p[];
       int c=-1, pr=0;
        if(symb=="0") { symb=Symbol();}
         for(int i=PositionsTotal()-1;i>=0;i--){
            if(position.SelectByIndex(i)) {
           if(position.PositionType()==POSITION_TYPE_BUY || position.PositionType()==POSITION_TYPE_SELL) {
            if((position.Symbol()==symb||symb=="")&&(type<0||position.PositionType()==type)&&(mg<0||position.Magic()==mg)) {
             c++;
             ArrayResize(p, c+1);
             p[c]=position.Time();
             pr=c>=index?index:c;
             
       }}}}
        return(c==-1?0:p[pr]);
       }

      ポジションの収益性を把握し、賭けに勝ったかどうかの判断をするには、現在時刻のポジションの利益を返す関数を使用することになります。手数料、スワップは考慮していません。

      //+------------------------------------------------------------------+
      //| Get profit in positions                                          |
      //+------------------------------------------------------------------+
      double GetProfit(string symb="0", int type=-1, int mg=-1,int index=0) {
       double p[];
       int c=-1, pr=0;
        if(symb=="0") { symb=Symbol();}
         for(int i=PositionsTotal()-1;i>=0;i--){
            if(position.SelectByIndex(i)) {
           if(position.PositionType()==POSITION_TYPE_BUY || position.PositionType()==POSITION_TYPE_SELL) {
            if((position.Symbol()==symb||symb=="")&&(type<0||position.PositionType()==type)&&(mg<0||position.Magic()==mg)) {
             c++;
             ArrayResize(p, c+1);
             p[c]=position.Profit();
             pr=c>=index?index:c;
             
       }}}}
        return(c==-1?0:p[pr]);
       }

      新しく入ってきたシグナルだけを処理するために、複数のトリガーを適用します。つまり、新しいシグナルが出たときにのみ、エントリの許可が発生します。同じシグナルで何度も入力しても無視されます。

      1. TrigerSell:Putオプションの買い
      2. TrigerBuy:Calオプションの買い
      int TrigerSell=0;
      int TrigerBuy=0;

      ポジションのエグジット、初期入金からの資金の追加と減少、オプションの購入の採算と不採算の計算は、現在時刻とポジションが開かれた時刻に対する有効期限を追跡することによっておこなわれます。

      //Sell (Put)
         
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)>0) && (TimeCurrent()>=(GetTime(symbolS1.Name(), POSITION_TYPE_SELL, Magic, 0)+(XExpirationTime*60)))){
          if(GetProfit(symbolS1.Name(), POSITION_TYPE_SELL, Magic, 0)>0){
           XStartDepo=XStartDepo+((OptionRate*ProfitPercent)/100);
           Profit++;
          }
          else{
           XStartDepo=XStartDepo-OptionRate;
           Loss++;
          }
         Comment("Depo = ",XStartDepo," Profit = ",Profit," Loss = ",Loss); 
         ClosePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment);
         }
      
      //Buy (Call)
         
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)>0) && (TimeCurrent()>=(GetTime(symbolS1.Name(), POSITION_TYPE_BUY, Magic, 0)+(XExpirationTime*60)))){
          if(GetProfit(symbolS1.Name(), POSITION_TYPE_BUY, Magic, 0)>0){
           XStartDepo=XStartDepo+((OptionRate*ProfitPercent)/100);
           Profit++;
          }
          else{
           XStartDepo=XStartDepo-OptionRate;
           Loss++;
          }
         Comment("Depo = ",XStartDepo," Profit = ",Profit," Loss = ",Loss); 
         ClosePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment);
         }

      最適化のために、変数を使用して、希望する時間枠と有効期限を決定します。最適化モードはOptimization変数で有効になります。最適化の本質は、CSVのようなファイルの使い方に尽きます。OnDeinitでテストが完了したら、必要な変数をファイルに書き込みます。最適化の際、エキスパートアドバイザー(EA)は「C:\Users\Your username\AppData\Roaming\MetaQuotes\Terminal\Common\Files」に結果をまとめたCSVファイルを作成します。

      1. 最終残高
      2. 収益を伴う取引の数
      3. 損失を伴う取引の数
      4. 時間枠
      5. 有効期限
      //+------------------------------------------------------------------+
      //| Expert deinitialization function                                 |
      //+------------------------------------------------------------------+
      void OnDeinit(const int reason)
        {
      
      if (Optimization==true){
       if (FileIsExist(OptimizationFileName)==false){
         filehandle = FileOpen(OptimizationFileName,FILE_WRITE|FILE_READ|FILE_CSV|FILE_COMMON|FILE_ANSI, ";");
          if(filehandle!=INVALID_HANDLE)
           {
            FileSeek(filehandle, 0, SEEK_END);
            FileWrite(filehandle,DoubleToString(XStartDepo),IntegerToString(Profit),IntegerToString(Loss),IntegerToString(XTimeFrame),IntegerToString(XExpirationTime));
            FileClose(filehandle);
           }
       }
      }
      
        }

      ビジュアライゼーションモードでテストを見ることができます。簡易化のためにComment()を使って現在の結果を表示することにしましょう。

      現在の結果


      ストラテジー

      2Ma+RSI+ストキャスティクスストラテジー

      この戦略は、バイナリーオプションのスキャルピング戦略として、ある有名な証券会社から提供されています。推奨時間枠は5分です。有効期限は5分です。

      指標:

      1. 期間5と10の指数移動平均のペア
      2. RSI(初期設定)
      3. ストキャスティックス(設定値14、3、3)

      次の条件が揃ったときに「アップ」シグナル(Callオプションの買い)を形成します。

      1. 赤い移動平均線が青い移動平均線を上向きで交差した
      2. RSIが50を超えている
      3. ストキャスティクスの高速線が低速線(点線)を上向きで交差した

      上向き戦略1

      「ダウン」シグナル(Putオプションの買い)は、次の要因が揃った場合に形成します。
      1. 赤いMAが青いMAを下向きに交差した
      2. RSIが50以下に位置している
      3. ストキャスティックスの高速線が低速線を下向きに交差した

      下向きストラテジー1

      この新しいシグナル戦略では、逆方向のMAの交差をトリガーとして選択しました。ストラテジーのコードは以下のようになります。

      //Sell (Put)
      
      if((ind_In1S1[1]>ind_In2S1[1]) && (ind_In1S1[2]>ind_In2S1[2])){TrigerSell=1;}
      
         if ((TrigerSell==1) && (CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)==0) && (ind_In1S1[1]<ind_In2S1[1]) && (ind_In1S1[0]<ind_In2S1[0]) && (ind_In4S1[1]<50) && (ind_In4S1[0]<50) && (ind_In3S1_1[1]<ind_In3S1_2[1])){
         OpenSell(symbolS1.Name(), 0.01, 0, 0, EAComment);
         TrigerSell=0;
         }
         
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)>0) && (TimeCurrent()>=(GetTime(symbolS1.Name(), POSITION_TYPE_SELL, Magic, 0)+(XExpirationTime*60)))){
          if(GetProfit(symbolS1.Name(), POSITION_TYPE_SELL, Magic, 0)>0){
           XStartDepo=XStartDepo+((OptionRate*ProfitPercent)/100);
           Profit++;
          }
          else{
           XStartDepo=XStartDepo-OptionRate;
           Loss++;
          }
         Comment("Depo = ",XStartDepo," Profit = ",Profit," Loss = ",Loss); 
         ClosePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment);
         }
      
      //Buy (Call)
      
      if((ind_In1S1[1]<ind_In2S1[1]) && (ind_In1S1[2]<ind_In2S1[2])){TrigerBuy=1;}
      
         if ((TrigerBuy==1) && (CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)==0) && (ind_In1S1[1]>ind_In2S1[1]) && (ind_In1S1[0]>ind_In2S1[0]) && (ind_In4S1[1]>50) && (ind_In4S1[0]>50) && (ind_In3S1_1[1]>ind_In3S1_2[1])){
         OpenBuy(symbolS1.Name(), 0.01, 0, 0, EAComment);
         TrigerBuy=0;
         }
         
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)>0) && (TimeCurrent()>=(GetTime(symbolS1.Name(), POSITION_TYPE_BUY, Magic, 0)+(XExpirationTime*60)))){
          if(GetProfit(symbolS1.Name(), POSITION_TYPE_BUY, Magic, 0)>0){
           XStartDepo=XStartDepo+((OptionRate*ProfitPercent)/100);
           Profit++;
          }
          else{
           XStartDepo=XStartDepo-OptionRate;
           Loss++;
          }
         Comment("Depo = ",XStartDepo," Profit = ",Profit," Loss = ",Loss); 
         ClosePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment);
         }

      このテストでは、次のような結果が得られました。

      • 最終残高:1964
      • 利益を伴う取引:1273
      • 損失を伴う取引:1822

      結果

      最適化の後、結果を得ます。見ての通り、どの時間帯、どの有効期限でも初期入金が増えることはありませんでした。

      最適化結果


      マーベリック戦略

      これはマーベリックと名付けられた面白くてシンプルなオプション戦略です。2つのテクニカル分析指標がベースになっており、取引のエントリポイントとエグジットポイントを極めて正確に決定すると言われています。取引は1~5分の時間枠で提供されます。より多くのシグナルを受信するために、異なる資産の複数のチャートを同時に開くことができます。

      指標:

      1. ボリンジャーバンド20、StDev(標準偏差)2
      2. RSI指標RSIパラメータ:4(80と20の境界)

      上昇を予測:Callオプションを購入

      RSIが2未満の売られすぎ領域に入り、価格帯がボリンジャーバンドに触れるかそれを超えたら、最初の強気なローソクを待って、上昇取引に入ります。

      上向きの買い

      下降を予想:Putオプションを購入

      RSIが80を超える買われすぎ領域に入り、価格線がボリンジャーの上限を超えたら、最初の弱気ローソクを待って下降取引を開始します。

      下向きの買い

      新しいシグナルトリガーとして、ボリンジャーチャンネルの内側での前のローソク足の終値を選択しました。ストラテジーのコードは以下のようになります。

      //Sell (Put)
      
      if(iClose(symbolS1.Name(),XTimeFrame,1)<ind_In1S1_1[1]){TrigerSell=1;}
      
         if ((TrigerSell==1) && (CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)==0) && (iClose(symbolS1.Name(),XTimeFrame,2)>ind_In1S1_1[2]) && (ind_In2S1[2]>80) && (iClose(symbolS1.Name(),XTimeFrame,1)<iOpen(symbolS1.Name(),XTimeFrame,1))){
         OpenSell(symbolS1.Name(), 0.01, 0, 0, EAComment);
         TrigerSell=0;
         }
         
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)>0) && (TimeCurrent()>=(GetTime(symbolS1.Name(), POSITION_TYPE_SELL, Magic, 0)+(XExpirationTime*60)))){
          if(GetProfit(symbolS1.Name(), POSITION_TYPE_SELL, Magic, 0)>0){
           XStartDepo=XStartDepo+((OptionRate*ProfitPercent)/100);
           Profit++;
          }
          else{
           XStartDepo=XStartDepo-OptionRate;
           Loss++;
          }
         Comment("Depo = ",XStartDepo," Profit = ",Profit," Loss = ",Loss); 
         ClosePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment);
         }
      
      //Buy (Call)
      
      if(iClose(symbolS1.Name(),XTimeFrame,1)>ind_In1S1_2[1]){TrigerBuy=1;}
      
         if ((TrigerBuy==1) && (CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)==0) && (iClose(symbolS1.Name(),XTimeFrame,2)<ind_In1S1_2[2]) && (ind_In2S1[2]<20) && (iClose(symbolS1.Name(),XTimeFrame,1)>iOpen(symbolS1.Name(),XTimeFrame,1))){
         OpenBuy(symbolS1.Name(), 0.01, 0, 0, EAComment);
         TrigerBuy=0;
         }
         
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)>0) && (TimeCurrent()>=(GetTime(symbolS1.Name(), POSITION_TYPE_BUY, Magic, 0)+(XExpirationTime*60)))){
          if(GetProfit(symbolS1.Name(), POSITION_TYPE_BUY, Magic, 0)>0){
           XStartDepo=XStartDepo+((OptionRate*ProfitPercent)/100);
           Profit++;
          }
          else{
           XStartDepo=XStartDepo-OptionRate;
           Loss++;
          }
         Comment("Depo = ",XStartDepo," Profit = ",Profit," Loss = ",Loss); 
         ClosePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment);
         }

      チェックを開始しましょう。M5でテストを実施してみましょう。以下の結果を得ます。

      • 最終残高:3312
      • 利益を伴う取引:1589
      • 損失を伴う取引:1940

      結果

      損失を被りました。結果は、前回の戦略より若干良くなっていますが。預金額が増えることを期待して、最適化を実行しましょう。残念ながら、この戦略はうまくいきません。

      最適化結果


      Vortex+TSIストラテジー

      バイナリーオプションの攻略法は、同名の指標を使用するため、Vortexと呼ばれています。実際、この戦略では、メインの指標とフィルタとしての2番目の指標の2つを使用します。1~5分の時間枠が推奨されています。

      指標:

      1. Vortex 14
      2. トゥルーストレングス指標(TSI)25、13、5、指数

      Callオプションの購入:

      1. 青い線が上向き、赤い線が下向きになったときに、両指標の線が同時に交差するのを待機
      2. Vortex指標ラインが発散

      成長

      Putオプションの購入:

      1. 赤い線が上向きで、青い線が下向きになるとき、両方の指標の線が同時に交差するのを待機
      2. Vortex指標ラインが発散

      下向き

      トゥルーストレングス指標の逆クロスが新たなシグナルトリガーとなります。ストラテジーのコードは以下のようになります。
      //Sell (Put)
      
      if(ind_In1S1_1[1]>ind_In1S1_2[1]){TrigerSell=1;}
      
         if ((TrigerSell==1) && (CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)==0) && (ind_In1S1_1[0]<ind_In1S1_2[0]) && (ind_In1S1_1[1]<ind_In1S1_2[1]) && (ind_In2S1_1[0]<ind_In2S1_2[0]) && (ind_In2S1_1[1]<ind_In2S1_2[1]) && (ind_In2S1_1[0]<ind_In2S1_1[1]) && (ind_In2S1_2[0]>ind_In2S1_2[1]) && (ind_In2S1_1[1]<ind_In2S1_1[2]) && (ind_In2S1_2[1]>ind_In2S1_2[2])){
         OpenSell(symbolS1.Name(), 0.01, 0, 0, EAComment);
         TrigerSell=0;
         }
         
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)>0) && (TimeCurrent()>=(GetTime(symbolS1.Name(), POSITION_TYPE_SELL, Magic, 0)+(XExpirationTime*60)))){
          if(GetProfit(symbolS1.Name(), POSITION_TYPE_SELL, Magic, 0)>0){
           XStartDepo=XStartDepo+((OptionRate*ProfitPercent)/100);
           Profit++;
          }
          else{
           XStartDepo=XStartDepo-OptionRate;
           Loss++;
          }
         Comment("Depo = ",XStartDepo," Profit = ",Profit," Loss = ",Loss); 
         ClosePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment);
         }
      
      //Buy (Call)
      
      if(ind_In1S1_1[1]<ind_In1S1_2[1]){TrigerBuy=1;}
      
         if ((TrigerBuy==1) && (CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)==0) && (ind_In1S1_1[0]>ind_In1S1_2[0]) && (ind_In1S1_1[1]>ind_In1S1_2[1]) && (ind_In2S1_1[0]>ind_In2S1_2[0]) && (ind_In2S1_1[1]>ind_In2S1_2[1]) && (ind_In2S1_1[0]>ind_In2S1_1[1]) && (ind_In2S1_2[0]<ind_In2S1_2[1]) && (ind_In2S1_1[1]>ind_In2S1_1[2]) && (ind_In2S1_2[1]<ind_In2S1_2[2])){
         OpenBuy(symbolS1.Name(), 0.01, 0, 0, EAComment);
         TrigerBuy=0;
         }
         
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)>0) && (TimeCurrent()>=(GetTime(symbolS1.Name(), POSITION_TYPE_BUY, Magic, 0)+(XExpirationTime*60)))){
          if(GetProfit(symbolS1.Name(), POSITION_TYPE_BUY, Magic, 0)>0){
           XStartDepo=XStartDepo+((OptionRate*ProfitPercent)/100);
           Profit++;
          }
          else{
           XStartDepo=XStartDepo-OptionRate;
           Loss++;
          }
         Comment("Depo = ",XStartDepo," Profit = ",Profit," Loss = ",Loss); 
         ClosePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment);
         }

      そろそろ、指標戦略のテストを開始します。M5でテストを実施してみましょう。以下の結果を得ます。

      • 最終残高:3118
      • 利益を伴う取引:1914
      • 損失を伴う取引:2843

      損失を伴う取引の回数がより多いです。最後的に残高がマイナスになりました。もしかしたら、最適化が役に立つかもしれません。

      結果

      最適化の結果は自明です。

      最適化結果


      さらに10種類ほどの戦略を試しましたが、思うような結果が得られなかったので、自分なりの戦略を立てることにしました。そこで得た経験をもとに、別のアプローチに挑戦してみることにしました。ストラテジーはNewと名付けました。

      New戦略

      売られすぎと買われすぎの状況を戦略の中心にしていきます。また、平均値をつけることにしました。私はこのような決定には反対ですが、それでも結果を確認するのは興味深いことです。

      指標:

      エンベロープ 14, 0, 0,1シンプル方式を終値に適用しています。

      「上向き」のシグナル(Callオプションの購入):

      1. Ask価格がエンベロープ指標の下限線を下回る
      2. エンベロープ指標のボトムラインからAsk価格までのポイントの距離が、Distanceの値よりも大きい

      上向き

      「下向き」シグナル(Putオプションの購入):

      1. Bid価格がエンベロープ指標の上線を上回る
      2. Bid価格からEnvelopes指標線までのポイント距離がDistance値より大きい

      下方向

      この戦略では、トリガーは使用しません。条件を満たし、建玉がない場合、新しいエントリシグナルが常に監視されます。以下は、平均化を使用しない場合のストラテジーコードです。

      //Sell (Put)
      
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)==0) && (BidS1>(ind_In1S1_1[0]+(Distance*PointS1)))){
         OpenSell(symbolS1.Name(), 0.01, 0, 0, EAComment);
         }
         
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)>0) && (TimeCurrent()>=(GetTime(symbolS1.Name(), POSITION_TYPE_SELL, Magic, 0)+(XExpirationTime*60)))){
          if(GetProfit(symbolS1.Name(), POSITION_TYPE_SELL, Magic, 0)>0){
           XStartDepo=XStartDepo+((OptionRate*ProfitPercent)/100);
           Profit++;
          }
          else{
           XStartDepo=XStartDepo-OptionRate;
           Loss++;
          }
         Comment("Depo = ",XStartDepo," Profit = ",Profit," Loss = ",Loss); 
         ClosePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment);
         }
      
      //Buy (Call)
      
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)==0) && (AskS1<(ind_In1S1_2[0]-(Distance*PointS1)))){
         OpenBuy(symbolS1.Name(), 0.01, 0, 0, EAComment);
         }
         
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)>0) && (TimeCurrent()>=(GetTime(symbolS1.Name(), POSITION_TYPE_BUY, Magic, 0)+(XExpirationTime*60)))){
          if(GetProfit(symbolS1.Name(), POSITION_TYPE_BUY, Magic, 0)>0){
           XStartDepo=XStartDepo+((OptionRate*ProfitPercent)/100);
           Profit++;
          }
          else{
           XStartDepo=XStartDepo-OptionRate;
           Loss++;
          }
         Comment("Depo = ",XStartDepo," Profit = ",Profit," Loss = ",Loss); 
         ClosePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment);
         }

      M5でテストしてみましょう。距離=150です。平均化処理をおこなわない場合のテスト結果は、以下のスクリーンショットの通りです。

      結果1

      最終残高:8952、利益を伴う取引:874

      損失を伴う取引:804

      儲からないエントリより儲かるエントリの方が多いのですが、預金の一部を失ってしまいました。これがマイナスの期待値です。この方法では、連続した負けエントリが最大2回となり、平均化する際に有利に働くと思います。 

      平均化を使用せずに最適化した結果が下のスクリーンショットです。利便性とわかりやすさを考慮して、儲かる状況だけをレポートに掲載することにしました。

      最適化結果1

      平均化を追加しましょう。平均化されたエントリ数を制限することにしました。そのために、新しいパラメータAveragingを導入し、デフォルトでは4になっています。平均化ストラテジーのコードは以下です。

      //Sell (Put)
      
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)==0) && (BidS1>(ind_In1S1_1[0]+(Distance*PointS1)))){
         OpenSell(symbolS1.Name(), 0.01, 0, 0, EAComment);
         Print(((XOptionRate*LossIn)*LossIn));
         }
         
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)>0) && (TimeCurrent()>=(GetTime(symbolS1.Name(), POSITION_TYPE_SELL, Magic, 0)+(XExpirationTime*60)))){
          if(GetProfit(symbolS1.Name(), POSITION_TYPE_SELL, Magic, 0)>0){
           XStartDepo=XStartDepo+(((XOptionRate*LossIn)*ProfitPercent)/100);
           Profit++;
           LossIn=1;
          }
          else{
           XStartDepo=XStartDepo-(XOptionRate*LossIn);
           Loss++;
           LossIn++;
           if(LossIn>Averaging){LossIn=1;}
          }
         Comment("Depo = ",XStartDepo," Profit = ",Profit," Loss = ",Loss); 
         ClosePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment);
         }
      
      //Buy (Call)
      
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)==0) && (AskS1<(ind_In1S1_2[0]-(Distance*PointS1)))){
         OpenBuy(symbolS1.Name(), 0.01, 0, 0, EAComment);
         Print(((XOptionRate*LossIn)*LossIn));
         }
         
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)>0) && (TimeCurrent()>=(GetTime(symbolS1.Name(), POSITION_TYPE_BUY, Magic, 0)+(XExpirationTime*60)))){
          if(GetProfit(symbolS1.Name(), POSITION_TYPE_BUY, Magic, 0)>0){
           XStartDepo=XStartDepo+(((XOptionRate*LossIn)*ProfitPercent)/100);
           Profit++;
           LossIn=1;
          }
          else{
           XStartDepo=XStartDepo-(XOptionRate*LossIn);
           Loss++;
           LossIn++;
           if(LossIn>Averaging){LossIn=1;}
          }
         Comment("Depo = ",XStartDepo," Profit = ",Profit," Loss = ",Loss); 
         ClosePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment);
         }

      平均化した場合のテスト結果です。ようやく成功しました。

      平均化1

      次は、平均化した最適化結果です。

      最適化結果1

      取引で損失を被った後にレートを掛けることで、より興味深いオプションの結果が得られました。そのコードを以下に記載します。

      //Sell (Put)
      
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)==0) && (BidS1>(ind_In1S1_1[0]+(Distance*PointS1)))){
         OpenSell(symbolS1.Name(), 0.01, 0, 0, EAComment);
         Print(((XOptionRate*LossIn)*LossIn));
         }
         
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)>0) && (TimeCurrent()>=(GetTime(symbolS1.Name(), POSITION_TYPE_SELL, Magic, 0)+(XExpirationTime*60)))){
          if(GetProfit(symbolS1.Name(), POSITION_TYPE_SELL, Magic, 0)>0){
           XStartDepo=XStartDepo+((((XOptionRate*LossIn)*LossIn)*ProfitPercent)/100);
           Profit++;
           LossIn=1;
          }
          else{
           XStartDepo=XStartDepo-((XOptionRate*LossIn)*LossIn);
           Loss++;
           LossIn++;
           if(LossIn>Averaging){LossIn=1;}
          }
         Comment("Depo = ",XStartDepo," Profit = ",Profit," Loss = ",Loss); 
         ClosePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment);
         }
      
      //Buy (Call)
      
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)==0) && (AskS1<(ind_In1S1_2[0]-(Distance*PointS1)))){
         OpenBuy(symbolS1.Name(), 0.01, 0, 0, EAComment);
         Print(((XOptionRate*LossIn)*LossIn));
         }
         
         if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)>0) && (TimeCurrent()>=(GetTime(symbolS1.Name(), POSITION_TYPE_BUY, Magic, 0)+(XExpirationTime*60)))){
          if(GetProfit(symbolS1.Name(), POSITION_TYPE_BUY, Magic, 0)>0){
           XStartDepo=XStartDepo+((((XOptionRate*LossIn)*LossIn)*ProfitPercent)/100);
           Profit++;
           LossIn=1;
          }
          else{
           XStartDepo=XStartDepo-((XOptionRate*LossIn)*LossIn);
           Loss++;
           LossIn++;
           if(LossIn>Averaging){LossIn=1;}
          }
         Comment("Depo = ",XStartDepo," Profit = ",Profit," Loss = ",Loss); 
         ClosePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment);
         }

      興味深いバリアントを最適化した結果です。

      最適化結果2


      結論

      すべての作業から、どのような結論が導き出されるのでしょうか。すべての指標戦略の99%は、実質的に機能しません。方法を少し変えることで、収益性の高い戦略を立てることが可能です。市場にエントリする前にすべてを確認することが必要です。いつものように、MetaTrader 5がこれを助けてくれます。ところで、100%の収益性を持つオプションがすでにあり、これがさらに考える材料になります。検討されたすべてのストラテジーは、エキスパートアドバイザーの形で、添付のアーカイブからダウンロードできます。


      MetaQuotes Ltdによってロシア語から翻訳されました。
      元の記事: https://www.mql5.com/ru/articles/12103

      添付されたファイル |
      MQL5.zip (24.76 KB)
      データサイエンスと機械学習(第10回):リッジ回帰 データサイエンスと機械学習(第10回):リッジ回帰
      リッジ回帰は、モデルの複雑さを軽減し、単純な線形回帰に起因する過学習を防ぐためのシンプルな手法です。
      MQL5クックブック - マクロ経済イベントデータベース MQL5クックブック - マクロ経済イベントデータベース
      この記事では、SQLiteエンジンに基づいてデータベースを処理する可能性について説明します。CDatabaseクラスは、OOP原則を便利かつ効率的に使用するために作成されました。その後、マクロ経済イベントのデータベースの作成と管理に関与しています。この記事では、CDatabaseクラスの複数のメソッドを使用する例を示します。
      自動で動くEAを作る(第08回):OnTradeTransaction 自動で動くEAを作る(第08回):OnTradeTransaction
      今回は、受注システムに関する問題を迅速かつ効率的に処理するためのイベント処理システムの使用方法について紹介します。このシステムにより、EAは必要なデータを常に検索する必要がなくなり、より速く動作するようになります。
      自動で動くEAを作る(第07回):口座の種類(II) 自動で動くEAを作る(第07回):口座の種類(II)
      今日は、自動モードでシンプルかつ安全に動作するエキスパートアドバイザー(EA)を作成する方法を紹介します。トレーダーは、自動EAが何をしているのかを常に意識しておく必要があります。そうすれば、もしEAが「レールから外れた」場合、トレーダーはできるだけ早くチャートからEAを取り除き、状況をコントロールすることができます。