English Deutsch
preview
PythonとMQL5を使用した取引戦略の自動パラメータ最適化

PythonとMQL5を使用した取引戦略の自動パラメータ最適化

MetaTrader 5 | 16 8月 2024, 15:01
18 0
Javier Santiago Gaston De Iriarte Cabrera
Javier Santiago Gaston De Iriarte Cabrera

自動最適化が不可欠な理由

苦労して開発した取引ボットがあるとしましょう。実際に使うのがすごく嬉しいのですが、適切な最適化なしに使い始めます。最初の好結果に惑わされ、すべてがうまくいっているように思っても、すぐに矛盾や損失が現れます。

最適化されていないボットは一貫性に欠け、無関係なデータに反応する可能性があり、予測不可能な利益や損失につながります。誤ったシグナルに基づいて意思決定をおこない、市場の変化に適応できず、予期せぬリスクを冒して大きな損失を出すかもしれません。最適化により、パフォーマンスと信頼性が向上します。

読者は、自動最適化の重要性と使用されるさまざまなアルゴリズムを理解し、Pythonとエキスパートアドバイザー(EA)スクリプトで実践的な例を見ることができます。自動最適化の設定、結果の比較、パラメータ最適化の適切な設定方法を学び、取引戦略の効率を高めます。

取引戦略の自己最適化アルゴリズムには、パラメータ最適化、進化的アルゴリズム、ヒューリスティック手法、勾配ベースの手法、機械学習、シミュレーションベースの最適化などがあります。それぞれに長所と短所があり、異なる取引ニーズや市場状況に合わせて調整されています。


パラメータ最適化技術

  1. 総当たり攻撃最適化:正確な結果を得るためにすべてのパラメータの組み合わせをテストします。リソースを大量に消費します。
  2. グリッド検索:グリッド内の組み合わせを評価し、バランスのとれた徹底性と効率性を追求します。
  3. ランダム検索:迅速な結果を得るために組み合わせをランダムにテストします。

それぞれの技術には長所があり、利用可能なリソース、時間、希望する精度によって選択することになります。


なぜ、どんなときにPythonを使用するのか?

Pythonプログラムは、アイデアを試したり、グラフィックを素早く作成したり、過去の取引データで理論的な主張を確認したりするための優れたツールです。Pythonを使用すれば、機動的にモデルを開発調整することができ、さまざまな戦略やパラメータの実験が容易になります。詳細なグラフやビジュアライゼーションを生成する機能は、結果をより直感的に解釈するのに役立ちます。さらに、過去のデータを統合することで、過去のシナリオでどのように戦略が機能したかを検証することができ、提起された理論に実際的な検証を与えることができます。スピード、柔軟性、分析能力を兼ね備えたPythonは、戦略を最適化し、金融市場をより深く理解しようとするトレーダーにとって、かけがえのないツールとなります。


この記事で使用する戦略とその指標

Mobile Sox Crossing戦略 (MAs Crossing)は、2本の移動平均線の交差に基づき、売買シグナルを生成する取引手法です。これは、価格のトレンドの変化を識別するために、期間の異なる2つの移動平均線(1つは短くもう1つは長い)を使用します。短いMAが長いMAを上回ると買いシグナルが発生し、強気トレンドの可能性を示唆します。逆に、短いMAが長いMAを下回ると売りシグナルが発生し、弱気トレンドの可能性を示唆します。この戦略はシンプルで、トレンドが明確な市場で有効なため人気があります。

SMA(Simple Moving Average、単純移動平均)指標は、特定期間の資産の平均価格を計算するツールです。SMAを計算するには、選択した期間中の資産の終値を加算し、期間数で割ります。SMAは価格の変動を滑らかにし、トレンドの大まかな方向性を特定するのに役立ちます。この指標は、市場のノイズを排除し、基本的なトレンドをより明確に把握するのに役立ちます。Pythonでは、移動平均を効率的かつ正確に計算する関数を提供するpandasなどのライブラリを使用して、SMAを簡単に計算することができます。


Pythonによるパラメータの最適化:ケーススタディ

Pythonのスクリプトを各手法に1つずつ用意しました。それぞれのアプローチの違いはすでに見てきました。

戦略は3つのスクリプトを通じて同じです。もし別の戦略を使用したいのであれば、これを変更すべきです。

    data = data.copy()  # Create a copy of the original DataFrame
    data['Short_MA'] = data['Close'].rolling(window=short_window).mean()
    data['Long_MA'] = data['Close'].rolling(window=long_window).mean()
    data['Signal'] = 0
    data.loc[data.index[short_window:], 'Signal'] = np.where(
        data['Short_MA'][short_window:] > data['Long_MA'][short_window:], 1, 0)
    data['Position'] = data['Signal'].diff()

Pythonはとても簡単なので、コードの説明は省きます。

3つのスクリプトは記事に添付されています(b forec.py、grid search v2.py、random search v2.py)。

これらのスクリプトを使用する前に、ライブラリをインストールする必要があります。これにはpipを使用できます。

pip install numpy pandas matplotlib itertools MetaTrader5 random 

各スクリプトの結果は、この入力でこのように表示されます。

symbol = "EURUSD"
timeframe = mt5.TIMEFRAME_D1
start = pd.Timestamp("2020-01-01")
end = pd.Timestamp("2021-01-01")

総当たり攻撃

総当たり攻撃左

総当たり攻撃右

Best parameters: Short = 14.0, Long = 43.0
Best performance: 10014.176, Risk: 3.7431030827241524e-05

グリッド検索

グリッド検索左

グリッド検索右

Best parameters: Short = 14.0, Long = 43.0
Best performance: 10014.176, Risk: 3.7431030827241524e-05

ランダム検索

ランダム検索左

ランダム検索右

Best parameters: Short = 14.0, Long = 44.0
Best performance: 10013.697, Risk: 3.725494046576829e-05

これらのスクリプトは自動最適化されないので、各期間を選択して学習する必要があります。

しかし、他の戦略がより多くのパラメータと大きなレンジを持つことができるのに対し、この戦略はシンプルであることを考慮しなければなりません。


戦略を最適化する頻度は?

取引戦略を最適化することは、その有効性を長期にわたって維持するために極めて重要です。最適化の頻度とルックバックは、いくつかの要因、特に市場のボラティリティに左右されます。

1日間の期間で動作する取引戦略を開発していると想像してください。つまり、各シグナルは毎日の市場データに基づいています。ボラティリティはここで重要な役割を果たします。市場のボラティリティが高ければ、値動きはより大きく、より速くなります。適切に適合しないと、戦略の有効性に影響する可能性があります。

いつ最適化し、どのようなルックバックを使用するかを決めるには、市場のボラティリティをモニターする必要があります。そのためには、日々の値幅(高値~安値)、または運用資産の真の平均値幅を観察するのが良い方法です。以下はボラティリティに基づくおおよその目安です。

低ボラティリティ:市場が落ち着いていて、1日の値幅が小さいときは、戦略の調整回数が少なくて済む傾向があります。より安定したトレンドを把握するために、1~3ヶ月ごとに、より長いルックバックで最適化することも考えられます。50~100日のルックバックが適切でしょう。

中ボラティリティ:定期的ではあるが、極端に大きな値動きがない通常の市場環境では、1~2ヶ月ごとに最適化することを検討します。トレンドの重要な変化を捉えるには、20~50日間のルックバックで十分でしょう。

高ボラティリティ:危機的な状況や重要な経済イベントなど、ボラティリティが高い時期には、値動きは大きく、速くなります。この場合、より頻繁に、場合によっては2~4週間ごとに最適化をおこない、10~20日といった短いルックバックを用いて、市場環境の変化に素早く対応することが肝要です。


MQL5の自己最適化の例

このMQL5コードは、移動平均(MA)交差戦略を実装した自動売買ロボットのもので、MetaTrader 5プラットフォーム上で動作し、金融市場で自動的に動作するように設計されています。このボットは、調整可能な期間を持つ2つの単純MA(SMA)を使用し、それらが交差したときに売買シグナルを生成します。

ボットの主な目的は、ユーザーが選択した設定に従って、正味利益を最大化、ドローダウンを最小化、またはシャープを最大化するために、MA期間を自動的に最適化することです。これは、特定の期間の履歴データでMA期間のさまざまな組み合わせをテストする最適化プロセスによって達成されます。

ボットはいくつかの重要なセクションで構成されています。

1.   初期化と設定:MA期間、ロットサイズ、注文ID用のマジックナンバーなどの初期パラメータを定義します。

2.   最適化:網羅的検索アルゴリズムを使用して、指定された範囲内のMA期間のすべての可能な組み合わせをテストします。選択された基準に基づいた最適化:正味利益または最小ドローダウン。

3.  操作の実行:市場を継続的に監視し、定義された戦略に従ってMA交差が発生した際に買いまたは売りのポジションを建てます。また、ポジションを管理し、ATR(Average True Range:平均真の値幅)に基づいて損失と利益水準を適用します。

4.  自動再最適化:特定の時間帯(設定可能)になると、ボットは市場の状況の変化に適応するためにMAのパラメータを再最適化します。

5.   トレーリングストップ:利益を確保し、損失から保護するために、さまざまなタイプのトレーリングストップ(単純ストップとモラル期待ストップ)を導入します。

6.  訓練のスケジュール:特定の曜日や時間帯に稼働しないように設定することもできます。

7.  完成と清算:ロボットは、停止時に開いているすべての操作の適切なクリーニングとクローズ操作を実行します。

要約すると、この自動売買ロボットは、テクニカル分析(MAの交差)とリスク管理戦略(ストップとトレーリングストップ)と自動化されたパラメータ最適化を組み合わせた複雑な実装を持ちます。これは自律的に動作するように設計されており、自動取引環境においてリスクに調整されたパフォーマンスを最大化するように最適化されています。

記事とコードで使用されているトレーリングストップは、Aleksej Poljakov著の「取引におけるトレーリングストップ」稿から入手したものです。

 


コード

別の最適化テクニックを使用するには、コードのこの部分を変更する必要があります。

   for(int fastPeriod = FastMAPeriodStart; fastPeriod <= FastMAPeriodStop; fastPeriod += FastMAPeriodStep)
     {
      for(int slowPeriod = SlowMAPeriodStart; slowPeriod <= SlowMAPeriodStop; slowPeriod += SlowMAPeriodStep)
        {
         double criterionValue = PerformBacktest(fastPeriod, slowPeriod, startBar);

         if(IsNewOptimal(criterionValue, bestCriterionValue, OptimizationCriterion))
           {
            bestCriterionValue = criterionValue;
            bestFastPeriod = fastPeriod;
            bestSlowPeriod = slowPeriod;
           }
        }
     }

別の戦略を使用するには、コードのこの部分(とその入力)を変更する必要があります。

double fastMA_curr[];
   double slowMA_curr[];
   double fastMA_prev[];
   double slowMA_prev[];

   ArraySetAsSeries(fastMA_curr, true);
   ArraySetAsSeries(slowMA_curr, true);
   ArraySetAsSeries(fastMA_prev, true);
   ArraySetAsSeries(slowMA_prev, true);

   int fastMA_current = iMA(_Symbol, 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
   int fastMA_previous = iMA(_Symbol, 0, FastMAPeriod, 1, MODE_SMA, PRICE_CLOSE);

   int slowMA_current = iMA(_Symbol, 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
   int slowMA_previous = iMA(_Symbol, 0, SlowMAPeriod, 1, MODE_SMA, PRICE_CLOSE);


   CopyBuffer(fastMA_current, 0, 0, 2, fastMA_curr);
   CopyBuffer(slowMA_current, 0, 0, 2, slowMA_curr);
   CopyBuffer(fastMA_previous, 0, 0, 2, fastMA_prev);
   CopyBuffer(slowMA_previous, 0, 0, 2, slowMA_prev);

   double fastMA_previousFF = fastMA_prev[0];
   double slowMA_previousSS = slowMA_prev[0];
   double fastMA_currentFF = fastMA_curr[0];
   double slowMA_currentSS = slowMA_curr[0];

// Check for buy signal (fast MA crosses above slow MA)
   if(fastMA_previousFF < slowMA_previousSS && fastMA_currentFF > slowMA_currentSS)
     {
      // Close any existing sell positions
      if(PositionsTotal() > 0)
        {
         for(int i = PositionsTotal() - 1; i >= 0; i--)
           {
            if(PositionSelectByTicket(i))
              {
               if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
                 {
                  Print("Closing sell position: Ticket ", PositionGetInteger(POSITION_TICKET));
                  ClosePosition(PositionGetInteger(POSITION_TICKET));
                 }
              }
           }
        }

      // Open a buy position
      double openPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
      double atrMultiplier = ATRmultiplier;
      OpenPosition(ORDER_TYPE_BUY, openPrice, atrMultiplier);
     }

// Check for sell signal (fast MA crosses below slow MA)
   else
      if(fastMA_previousFF > slowMA_previousSS && fastMA_currentFF < slowMA_currentSS)
        {
         // Close any existing buy positions
         if(PositionsTotal() > 0)
           {
            for(int i = PositionsTotal() - 1; i >= 0; i--)
              {
               if(PositionSelectByTicket(i))
                 {
                  if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
                    {
                     Print("Closing buy position: Ticket ", PositionGetInteger(POSITION_TICKET));
                     ClosePosition(PositionGetInteger(POSITION_TICKET));
                    }
                 }
              }
           }

         // Open a sell position
         double openPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         double atrMultiplier = ATRmultiplier;
         OpenPosition(ORDER_TYPE_SELL, openPrice, atrMultiplier);

        }
   IndicatorRelease(fastMA_current);
   IndicatorRelease(slowMA_current);
   IndicatorRelease(fastMA_previous);
   IndicatorRelease(slowMA_previous);
  }

重要なのは、指標をリリースしないと、グラフウィンドウが指標で埋まってしまうことです。


自動最適化の有無による違い

EURUSDについては同じ期間(20-4-2024から20-5-2024まで)、日足の期間を使用します。

最適化設定

最適化

最適化入力

最適化によるバックテスト

最適化グラフ

自動最適化なし

自動最適化なしの入力

オートパラメトリゼーションなしのバックテスト

自動最適化なしのグラフ

明らかに、自動最適化の方が良い解決策です。自動最適化なしでは取引はおこなわれませんでした。最初は自動最適化され、その後40日間(期間外)で再最適化されました。


結論

自動最適化は、刻々と変化する金融市場において取引ボットの一貫した信頼できるパフォーマンスを確保する上で極めて重要です。この記事を通じて、読者は自己最適化が不可欠である理由、取引戦略とパラメータを最適化するために利用可能なさまざまな種類のアルゴリズム、さまざまなパラメータ最適化手法の利点と欠点について包括的に理解することができました。移動平均クロスオーバー戦略を使用したパラメータ最適化のケーススタディとともに、戦略を迅速かつ効率的にバックテストするツールとしてのPythonの重要性が強調されました。

さらに、市場のボラティリティに基づく定期的な最適化の必要性を追求し、有効性を維持するためには頻繁な調整が必要であることを強調しました。MQL5を使用した自己最適化の例では、自動最適化によって達成可能な大幅な性能向上を示し、これらの概念の実用的な適用を説明しました。自動最適化されたボットと最適化されていないボットの比較では、前者の明確な優位性が強調され、最適化されたボットは優れた適応性と効率性を示しました。

結論として、自動最適化は取引ボットのパフォーマンスを向上させるだけでなく、ボットが複雑な金融市場を効果的にナビゲートできることを知ることで、トレーダーに大きな自信と安心を提供します。取引ボットの開発とメンテナンスに対するこの戦略的アプローチは、取引で一貫して持続可能な成功を収めたいと真剣に考える人にとって不可欠なものです。


書籍と教材

  • Marcos López de Prado著「Advances in Financial Machine Learning」
  • Barry Johnson著「Algorithmic Trading and DMA」
  • Wes McKinney著「Python for Data Analysis」
  • Marcos López de Prado著「Machine Learning for Asset Managers」
  • Ernest P.著「Quantitative Trading:How To Build Your Own Algorithmic Trading Business」


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

添付されたファイル |
b_forec.py (3.64 KB)
grid_search_v2.py (3.64 KB)
リプレイシステムの開発(第42回):Chart Traderプロジェクト(I) リプレイシステムの開発(第42回):Chart Traderプロジェクト(I)
もっと面白いものを作りましょう。ネタバレはしたくないので、理解を深めるために記事を読んでください。リプレイ/シミュレーターシステムの開発に関する本連載の最初の段階から、私は、開発中のシステムと実際の市場の両方で同じようにMetaTrader 5プラットフォームを使用することがアイディアであると述べてきました。これが適切におこなわれることが重要です。ある道具を使用して訓練して戦い方を学んだ末、戦いの最中に別の道具を使用しなければならないというようなことは誰もしたくありません。
市場力学をマスターする:支持&抵抗戦略エキスパートアドバイザー(EA)の作成 市場力学をマスターする:支持&抵抗戦略エキスパートアドバイザー(EA)の作成
支持&抵抗戦略に基づく自動売買アルゴリズム開発のための包括的ガイドです。MQL5でEAを作成し、MetaTrader 5でテストするための、価格帯行動の分析からリスク管理までのあらゆる側面に関する詳細情報が含まれます。
知っておくべきMQL5ウィザードのテクニック(第24回):移動平均 知っておくべきMQL5ウィザードのテクニック(第24回):移動平均
移動平均は、ほとんどのトレーダーが使用し、理解している非常に一般的な指標です。この記事では、MQL5ウィザードで組み立てられたエキスパートアドバイザー(EA)の中で、あまり一般的ではないかもしれない使用例を探っていきます。
知っておくべきMQL5ウィザードのテクニック(第23回):CNN 知っておくべきMQL5ウィザードのテクニック(第23回):CNN
畳み込みニューラルネットワーク(Convolutional Neural Network: CNN)もまた、多次元のデータセットを主要な構成要素に分解することに特化した機械学習アルゴリズムです。一般的にどのように達成されるかを見て、別のMQL5ウィザードシグナルクラスのトレーダーへの応用の可能性を探ります。