English Русский 中文 Español Deutsch
preview
MQL5エキスパートアドバイザーに自動最適化を実装する方法

MQL5エキスパートアドバイザーに自動最適化を実装する方法

MetaTrader 5 | 14 11月 2024, 11:15
292 0
Javier Santiago Gaston De Iriarte Cabrera
Javier Santiago Gaston De Iriarte Cabrera

自動最適化外国為替取引アルゴリズムの素晴らしい世界に足を踏み入れる準備をしましょう。これにより、取引終了後の市場状況に基づいて、エキスパートアドバイザー(EA)が次の取引に向けて自動的に調整できるようになります。

EAを、移動平均を通じてトレンドを分析する有能なトレーダーと考えてみてください。これがうまくいっているとき、市場の変化に応じて戦略を学習し調整できるブラックボックスがあったらどうでしょうか。それが、自動最適化のプロセスです。

EAを使用する主な利点の1つは、市場状況が変化し続ける中で、最終的にその変化に適応できることです。EAは現在の市場環境に自動的に適応し、手動での監視やパラメータ変更が不要になります。これにより、トレーダーは、秒単位の短期的な機会を逃すことなく、取引戦略を中断することなく実行できます。また、EAは毎日1日中取引戦略を調整することができます。

しかし、注意すべき落とし穴もいくつかあります。課題のひとつは、最近のデータに過剰適合してしまうリスクです。これにより、異なる市場状況でパフォーマンスが低下する可能性があります。また、戦略を自動化することでコードが複雑になることがあり、計算リソースの管理が重要になります。パラメータ変更中に安定性を保つことは難しく、パフォーマンスの帰属問題が発生することもあります。

このガイドでは、カスタム指標を使用した戦略の自動化など、自動最適化EAの構築プロセスについて説明します。堅牢な最適化ロジック、パラメーター選択のベストプラクティス、バックテストを通じた戦略の再構築方法について解説します。さらに、ウォークフォワード最適化などの高レベルな手法を紹介し、取引アプローチの強化を目指します。

目標を達成し、生産性を高める方法(そして罠に陥らない方法)を一緒に学んでいきましょう。

私たちの取引計画は、移動平均クロスオーバー戦略に基づいています。これはすべての戦略の中でも最も基本的なものですが、トレンド市場では決して失敗しません。


1. EA自動最適化のためのライブラリ、入力パラメータ、最適化範囲の設定

1.1 必要なライブラリのインポート

最初の行で、必要なMQL5ライブラリをインクルードします。

#include <Trade\Trade.mqh>
#include <Arrays\ArrayObj.mqh>

Tradeライブラリは取引を実行するための関数を提供します。また、ArrayObjライブラリを使用すると、最適化の結果を保存するために使用するオブジェクトの動的配列を操作できます。

1.2 入力パラメータの定義

次に、EAの入力パラメーターを定義します。

input int MA_Fast_Period = 10;     // Fast Moving Average Period
input int MA_Slow_Period = 20;     // Slow Moving Average Period
input ENUM_MA_METHOD MA_Method = MODE_SMA; // Moving Average Method
input ENUM_APPLIED_PRICE Applied_Price = PRICE_CLOSE; // Applied Price
input double LotSize = 0.1;        // Lot Size
input int StopLoss = 50;           // Stop Loss in points
input int TakeProfit = 100;        // Take Profit in points

// Optimization parameters
input bool AutoOptimize = false;   // Enable Auto Optimization
input int OptimizationPeriod = 5000; // Number of ticks between optimizations
input int MinDataPoints = 1000;    // Minimum number of data points for optimization

これらの入力パラメータにより、ユーザーはEAの動作と最適化設定をMetaTraderインターフェイスから直接設定することができます。

1.3 グローバル変数とハンドル

次に、EA全体で使用されるグローバル変数とハンドルを宣言します。

CTrade trade;
int fastMA_Handle, slowMA_Handle;
double fastMA[], slowMA[];
int tickCount = 0;
CArrayObj* optimizationResults;

// Optimization ranges
const int MA_Fast_Min = 5, MA_Fast_Max = 50, MA_Fast_Step = 1;
const int MA_Slow_Min = 10, MA_Slow_Max = 100, MA_Slow_Step = 1;

CTradeオブジェクトは取引操作を処理し、fastMA_HandleとslowMA_Handleは移動平均指標を管理するために使用されます。最適化テストの結果はoptimizationResults配列に格納されます。

1.4 最適化設定

最適化設定では、各パラメータについてテストする値の範囲を定義します。

  • 高速MA期間:5から50まで1ずつ増加、低速MA期間:10から100まで1ずつ増加
これらの範囲は、特定の要件と取引する商品の特性に基づいて調整できます。


2. コア取引ロジックの実装

EA構造を設定したら、初期化、非初期化、ティック処理を処理するコア関数を実装しましょう。

2.1 OnInit()関数

OnInit()関数は、EAが初めてチャートにロードされたときに呼び出されます。実装方法は次のとおりです。

int OnInit()
{
    // Initialize MA handles
    fastMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Fast_Period, 0, MA_Method, Applied_Price);
    slowMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Slow_Period, 0, MA_Method, Applied_Price);
    
    if(fastMA_Handle == INVALID_HANDLE || slowMA_Handle == INVALID_HANDLE)
    {
        Print("Failed to create MA indicators");
        return INIT_FAILED;
    }
    
    // Initialize optimization results array
    optimizationResults = new CArrayObj();
    
    return INIT_SUCCEEDED;
}

この関数は移動平均指標を作成し、最適化結果配列を初期化します。指標の初期化に失敗した場合、EAは起動しません。

2.2 OnDeinit()関数

OnDeinit()関数は、EAがチャートから削除されたときや端末が閉じられたときに呼び出されます。

void OnDeinit(const int reason)
{
    // Release MA handles
    IndicatorRelease(fastMA_Handle);
    IndicatorRelease(slowMA_Handle);
    
    // Clean up optimization results
    if(optimizationResults != NULL)
    {
        delete optimizationResults;
        optimizationResults = NULL;
    }
}

この関数により、指標ハンドルが適切に解放され、最適化結果配列によって使用されるメモリが解放されます。

2.3 OnTick()関数

OnTick()関数はEAの心臓部であり、選択した銘柄のティックごとに呼び出されます。

void OnTick()
{
    // Check if we have enough bars to calculate MAs
    if(Bars(_Symbol, PERIOD_CURRENT) < MA_Slow_Period) return;
    
    // Copy MA values
    if(CopyBuffer(fastMA_Handle, 0, 0, 2, fastMA) != 2) return;
    if(CopyBuffer(slowMA_Handle, 0, 0, 2, slowMA) != 2) return;
    
    // Auto Optimization
    if(AutoOptimize && ++tickCount >= OptimizationPeriod)
    {
        Optimize();
        tickCount = 0;
    }
    
    // Trading logic
    if(fastMA[1] <= slowMA[1] && fastMA[0] > slowMA[0])
    {
        // Open buy position
        double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
        trade.Buy(LotSize, _Symbol, ask, ask - StopLoss * _Point, ask + TakeProfit * _Point);
    }
    else if(fastMA[1] >= slowMA[1] && fastMA[0] < slowMA[0])
    {
        // Open sell position
        double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
        trade.Sell(LotSize, _Symbol, bid, bid + StopLoss * _Point, bid - TakeProfit * _Point);
    }
}

この関数はいくつかの重要なタスクを実行します。

  1. 移動平均を計算するのに十分な過去のデータがあるかどうかを確認する。
  2. 移動平均の現在値を取得する。
  3. 自動最適化が有効で(ティックカウントに基づいて)最適化するタイミングになるとOptimize()関数を呼び出す。
  4. 移動平均のクロスオーバーに基づいて買いまたは売りのポジションを建てる取引ロジックを実装する。



3. 最適化ロジックの実装

自動最適化機能の中核はOptimize()関数にあります。その構成要素を分解して検証してみましょう。

3.1 Optimize()関数

以下はOptimize()関数の全体的な構造です。

void Optimize()
{
    Print("Starting optimization...");
    
    optimizationResults.Clear();
    
    // Loop through all combinations of MA periods
    for(int fastPeriod = MA_Fast_Min; fastPeriod <= MA_Fast_Max; fastPeriod += MA_Fast_Step)
    {
        for(int slowPeriod = MA_Slow_Min; slowPeriod <= MA_Slow_Max; slowPeriod += MA_Slow_Step)
        {
            if(slowPeriod <= fastPeriod) continue; // Slow period should be greater than fast period
            
            double profit = TestParameters(fastPeriod, slowPeriod);
            
            OptimizationResult* result = new OptimizationResult;
            result.fastPeriod = fastPeriod;
            result.slowPeriod = slowPeriod;
            result.profit = profit;
            
            optimizationResults.Add(result);
        }
    }
    
    // Find the best result
    OptimizationResult* bestResult = NULL;
    for(int i = 0; i < optimizationResults.Total(); i++)
    {
        OptimizationResult* currentResult = optimizationResults.At(i);
        if(bestResult == NULL || currentResult.profit > bestResult.profit)
        {
            bestResult = currentResult;
        }
    }
    
    if(bestResult != NULL)
    {
// Update the EA parameters
        MA_Fast_Period = bestResult.fastPeriod;
        MA_Slow_Period = bestResult.slowPeriod;
        
        // Update indicator handles
        IndicatorRelease(fastMA_Handle);
        IndicatorRelease(slowMA_Handle);
        fastMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Fast_Period, 0, MA_Method, Applied_Price);
        slowMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Slow_Period, 0, MA_Method, Applied_Price);
        
        Print("Optimization complete. New parameters: Fast MA = ", MA_Fast_Period, ", Slow MA = ", MA_Slow_Period);
    }
    else
    {
        Print("Optimization failed to find better parameters.");
    }
}

3.2 パラメーターの組み合わせのループ

Optimize()関数のネストされたforループを使うと、指定した範囲内で高速移動平均期間と低速移動平均期間のすべての組み合わせをテストできます。この方法は、組み合わせを1つずつ試すアプローチであるため、「総当たり攻撃」アプローチとして知られています。

for(int fastPeriod = MA_Fast_Min; fastPeriod <= MA_Fast_Max; fastPeriod += MA_Fast_Step)
{
    for(int slowPeriod = MA_Slow_Min; slowPeriod <= MA_Slow_Max; slowPeriod += MA_Slow_Step)
    {
        if(slowPeriod <= fastPeriod) continue; // Slow period should be greater than fast period
        
        double profit = TestParameters(fastPeriod, slowPeriod);
        
        // Store results...
    }
}

低速期間が高速期間以下である組み合わせはここでの戦略にとって意味がないのでスキップします。

3.3 結果の保存と比較

各有効な組み合わせについて、TestParameters()を呼び出してその性能を評価します。結果はOptimizationResultオブジェクトに格納されoptimizationResults配列に追加されます。

すべての組み合わせをテストした後、その結果をループして、最もパフォーマンスの良いパラメータセットを見つけます。

OptimizationResult* bestResult = NULL;
for(int i = 0; i < optimizationResults.Total(); i++)
{
    OptimizationResult* currentResult = optimizationResults.At(i);
    if(bestResult == NULL || currentResult.profit > bestResult.profit)
    {
        bestResult = currentResult;
    }
}

最良の結果が見つかった場合は、EAパラメータを更新し、新しい期間で指標ハンドルを再作成します。


4. テストパラメータ

TestParameters()関数は、各パラメータセットを評価するために重要です。詳しく見てみましょう。

4.1 TestParameters()関数

double TestParameters(int fastPeriod, int slowPeriod)
{
    int maFast = iMA(_Symbol, PERIOD_CURRENT, fastPeriod, 0, MA_Method, Applied_Price);
    int maSlow = iMA(_Symbol, PERIOD_CURRENT, slowPeriod, 0, MA_Method, Applied_Price);
    
    if(maFast == INVALID_HANDLE || maSlow == INVALID_HANDLE)
    {
        Print("Failed to create MA indicators for testing");
        return -DBL_MAX;
    }
    
    double fastBuffer[], slowBuffer[];
    ArraySetAsSeries(fastBuffer, true);
    ArraySetAsSeries(slowBuffer, true);
    
    int copied = CopyBuffer(maFast, 0, 0, MinDataPoints, fastBuffer);
    copied = MathMin(copied, CopyBuffer(maSlow, 0, 0, MinDataPoints, slowBuffer));
    
    if(copied < MinDataPoints)
    {
        Print("Not enough data for testing");
        return -DBL_MAX;
    }
    
    double profit = 0;
    for(int i = 1; i < copied; i++)
    {
        if(fastBuffer[i] > slowBuffer[i] && fastBuffer[i-1] <= slowBuffer[i-1])
        {
            // Buy signal
            profit += Close[i-1] - Open[i];
        }
        else if(fastBuffer[i] < slowBuffer[i] && fastBuffer[i-1] >= slowBuffer[i-1])
        {
            // Sell signal
            profit += Open[i] - Close[i-1];
        }
    }
    
    IndicatorRelease(maFast);
    IndicatorRelease(maSlow);
    
    return profit;
}

4.2 一時的な指標の作成

テストする各パラメータセットについて、一時的な移動平均指標を作成します。

int maFast = iMA(_Symbol, PERIOD_CURRENT, fastPeriod, 0, MA_Method, Applied_Price);
int maSlow = iMA(_Symbol, PERIOD_CURRENT, slowPeriod, 0, MA_Method, Applied_Price);

これらの一時的な指標を使用すると、メインの取引ロジックに影響を与えることなく、異なる期間の移動平均を計算できます。

4.3 取引のシミュレーション

次に、履歴データをループし、移動平均クロスオーバーロジックに基づいて取引をシミュレートします。

for(int i = 1; i < copied; i++)
{
    if(fastBuffer[i] > slowBuffer[i] && fastBuffer[i-1] <= slowBuffer[i-1])
    {
        // Buy signal
        profit += Close[i-1] - Open[i];
    }
    else if(fastBuffer[i] < slowBuffer[i] && fastBuffer[i-1] >= slowBuffer[i-1])
    {
        // Sell signal
        profit += Open[i] - Close[i-1];
    }
}

この簡略化されたシミュレーションでは、クロスオーバー後のバーの始値で取引を開始し、同じバーの終値で取引を終了できることを前提としています。

4.4 利益の計算

この関数は、シミュレートされた取引によって生成された合計利益を返します。より洗練された実装では、最大ドローダウン、シャープレシオ、勝率などの他の要素を考慮する場合があります。


5. 最適化されたパラメータの適用

最高のパフォーマンスを発揮するパラメータを見つけたら、それをEAに適用する必要があります。

5.1 EAパラメータの更新

新しい最適値でグローバル変数を更新します。

MA_Fast_Period = bestResult.fastPeriod;
MA_Slow_Period = bestResult.slowPeriod;

5.2 指標ハンドルの再現

パラメータを更新した後、指標のハンドルを再作成する必要があります。

IndicatorRelease(fastMA_Handle);
IndicatorRelease(slowMA_Handle);
fastMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Fast_Period, 0, MA_Method, Applied_Price);
slowMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Slow_Period, 0, MA_Method, Applied_Price);

これにより、当社の主要な取引ロジックは、今後、新たに最適化されたパラメータを使用することになります。


6. 高度な最適化技術

現在の実装は自動最適化のための強固な基盤を提供しますが、EAのパフォーマンスをさらに向上させるために検討できる高度なテクニックがいくつかあります。

6.1 多基準最適化

利益のみを最適化するのではなく、最適化プロセスに複数の基準を組み込むことができます。次は例です。

struct OptimizationResult
{
    int fastPeriod;
    int slowPeriod;
    double profit;
    double drawdown;
    double sharpeRatio;
};

double CalculateScore(const OptimizationResult &result)
{
    return result.profit * 0.5 + result.sharpeRatio * 0.3 - result.drawdown * 0.2;
}

このアプローチにより、パフォーマンスの複数の側面のバランスをとることができるため、より堅牢なパラメータセットを実現できる可能性があります。

6.2 ウォークフォワード最適化

ウォークフォワード最適化では、履歴データを複数のセグメントに分割し、1つのセグメントを最適化してから次のセグメントをテストします。

これは過剰適合を防ぐのに役立ちます。

void WalkForwardOptimization()
{
    int totalBars = Bars(_Symbol, PERIOD_CURRENT);
    int segmentSize = 1000; // Adjust as needed
    
    for(int i = 0; i < totalBars - 2*segmentSize; i += segmentSize)
    {
        // Optimize on segment i to i+segmentSize
        OptimizeSegment(i, i+segmentSize);
        
        // Test on segment i+segmentSize to i+2*segmentSize
        TestSegment(i+segmentSize, i+2*segmentSize);
    }
}

6.3 適応パラメータ調整

最適化中にパラメータを完全に置き換える代わりに、最近のパフォーマンスに基づいてパラメータを徐々に調整するシステムを実装できます。

void AdaptParameters()
{
    double recentPerformance = CalculateRecentPerformance();
    double adaptationRate = 0.1; // Adjust as needed
    
    MA_Fast_Period += (int)((bestResult.fastPeriod - MA_Fast_Period) * adaptationRate * recentPerformance);
    MA_Slow_Period += (int)((bestResult.slowPeriod - MA_Slow_Period) * adaptationRate * recentPerformance);
}

このアプローチにより、パラメータセット間の移行がスムーズになり、短期的な市場ノイズが最適化プロセスに与える影響を軽減できる可能性があります。



7. ベストプラクティスと考察

自動最適化EAを実装し、改良する際には、これらのベストプラクティスを念頭に置いてください。

7.1 最適化頻度の選択

最適化の頻度は、EAのパフォーマンスに大きな影響を与える可能性があります。最適化の頻度が高すぎると、短期的な市場変動に過剰反応する可能性がありますが、最適化の頻度が低すぎると、機会を逃す可能性があります。

市場のボラティリティやEAの最近のパフォーマンスに基づいて動的な最適化頻度を実装することを検討してください。

bool ShouldOptimize()
{
    double recentVolatility = CalculateRecentVolatility();
    int dynamicPeriod = (int)(OptimizationPeriod * (1 + recentVolatility));
    
    return tickCount >= dynamicPeriod;
}

7.2 適応性と安定性のバランス

適応性は自動最適化EAの主な利点ですが、ある程度の安定性を維持することも重要です。パラメータを大幅に変更すると、一貫性のない取引動作につながる可能性があります。

1回の最適化で変更できるパラメータの数に制限を設けることを検討してください。

void LimitParameterChange(int &parameter, int newValue, int maxChange)
{
    int change = newValue - parameter;
    change = MathMax(-maxChange, MathMin(change, maxChange));
    parameter += change;
}

7.3 過剰適合 過剰適合はあらゆる最適化プロセスで避けるべき大きなリスクです。過剰適合したEAは、過去データ上では非常に優れたパフォーマンスを示しますが、新しい市場状況に直面した際には期待通りの結果を出せない可能性があります。このリスクを軽減するためには、十分な量の過去データを最適化に使用することが大切です。加えて、サンプル外テストやウォークフォワード最適化を実装することで、EAの堅牢性を向上させることができます。また、利用可能なデータの量に応じて、戦略の複雑さを慎重に決定することも重要です。EAのライブパフォーマンスを注意深く監視することも欠かせません。EAの動作がバックテスト結果と大幅に異なる場合、状況に応じて迅速に介入する準備が必要です。

7.4 自動最適化 自動最適化は計算負荷が高いため、計算効率の確保が重要です。EAの応答性を保つためには、最適化プロセスをオフピークの時間帯に実行するか、別スレッドで処理することが推奨されます。効率的なデータ構造やアルゴリズムを用いることで、処理時間を大幅に短縮することが可能です。また、より集中的な最適化タスクが必要な場合には、クラウドベースのソリューションを活用することも一案です。


8.  自動最適化EAの開発は、デバッグとトラブルシューティングに新たな課題をもたらす

8.1 開発中には、いくつかの一般的な問題が発生する可能性があります。たとえば、EAが実行ごとに一貫性のない結果を出力する場合、まず一貫したデータを使用しているか、コード内にランダムな要素が含まれていないかを確認してください。また、バックテストで良好な結果が出ているにもかかわらず、ライブパフォーマンスが低い場合、スリッページやスプレッド、または市場状況の変化が原因である可能性があります。最適化が失敗したり、意図しない結果が生じた場合は、最適化基準を再確認し、TestParameters()関数が期待通りに動作しているかを確認することが重要です。

8.2 デバッグを支援するためには、包括的なログ記録の実装を強くお勧めします。これにより、EAの動作や最適化プロセスの詳細な追跡が可能になり、問題の特定と解決がより効果的におこなえるようになります。

EA の動作と最適化プロセスを追跡するための包括的なログ記録を実装します。
void Log(string message)
{
    Print(TimeToString(TimeCurrent()) + ": " + message);
    
    int handle = FileOpen("EA_Log.txt", FILE_WRITE|FILE_READ|FILE_TXT);
    if(handle != INVALID_HANDLE)
    {
        FileSeek(handle, 0, SEEK_END);
        FileWriteString(handle, TimeToString(TimeCurrent()) + ": " + message + "\n");
        FileClose(handle);
    }
}

この関数を使用して、重要なイベント、パラメータの変更、および操作中または最適化中に発生するエラーを記録します。

8.3 MetaTraderストラテジーテスターはEAをデバッグするための貴重なツールです。ビジュアルモードを使用すると、EAの動作をバーごとに段階的に確認することができ、EAがリアルタイムでどのように機能しているかを詳細に把握できます。さらに、ストラテジーテスターの最適化結果とEAの自動最適化結果を比較することで、不一致を特定することができます。ストラテジーテスターの最適化機能は、TestParameters()関数の機能を検証する有用な方法としても役立ちます。



9. 自動最適化移動平均EAの性能と課題

9.1 自動最適化の潜在的な利点と課題を説明するために、架空のケーススタディを考えてみましょう。

2010年から2020年までのEURUSDのH1データを用いて、自動最適化機能を備えた移動平均クロスオーバーEAのバックテストをおこないました。このEAは5000ティックごとにパラメータを最適化する設定となっており、テスト結果は非常に有望でした。全取引回数は1,247回、純利益は合計15,420ドル、利益率は1.65、最大ドローダウンは2,105ドルでした。

次に、静的パラメータ(MA_Fast_Period = 10、MA_Slow_Period = 20)を使用した同じEAとの比較をおこないました。静的バージョンの結果では、合計1,562回の取引で、純利益は8,750ドル、利益率は1.38、最大ドローダウンは3,210ドルとやや高くなりました。この比較により、自動最適化バージョンのEAは全体的な収益性とリスク調整後のリターンの両面で大きく改善されていることが確認されました。

9.2 バックテストの結果は有望ですが、実際のパフォーマンス評価の際にはいくつかの重要な要素を考慮する必要があります。たとえば、2008年の金融危機や2020年のCOVID-19パンデミックといった市場体制の変化は、EAの適応性に影響を及ぼす可能性があり、慎重な評価が必要です。さらに、取引コストも、収益性向上が取引回数の増加に見合うものかを判断するために考慮する必要があります。また、ライブ環境での継続的な最適化に必要な計算リソースや、EAが新しい状況に適応する際のパフォーマンス低下期間への対応に必要な心理的回復力も大切な要素です。


10. 自動最適化EAの今後の動向:機械学習、外部データ、クラウドソリューション

10.1 取引技術の進化に伴い、EAの自動最適化に関する画期的な開発が次々と生まれています。そのひとつが、機械学習アルゴリズムのForexトレーディングへの統合です。これにより、市場データ内に潜む複雑なパターンを発見し、最適化プロセスをより効果的に強化することが可能になります。将来的には、さらに適応性と効率性に優れたトレーディング戦略の実現が期待されます。

機械学習アルゴリズムは、膨大な市場データから見つかりにくいパターンを識別することで、最適化プロセスに新たなアプローチを提供します。

from sklearn.ensemble import RandomForestRegressor

def ml_optimize(data, labels):
    model = RandomForestRegressor(n_estimators=100)
    model.fit(data, labels)
    return model.feature_importances_

この例ではPythonを使用していますが、同様の機械学習技術はMQL5で実装することも、外部ライブラリを使って統合することもできます。

10.2 外部データソースとの統合

外部データ(経済指標、感情分析など)を最適化プロセスに組み込むと、市場の状況をより包括的に把握できます。

string GetExternalData()
{
    string cookie=NULL,headers;
    char post[],result[];
    int res;
    
    string url="https://api.example.com/economic-data";
    
    res=WebRequest("GET",url,cookie,NULL,500,post,0,result,headers);
    
    if(res==-1)
    {
        Print("Error in WebRequest. Error code  =",GetLastError());
        return "";
    }
    
    string resultString=CharArrayToString(result);
    return resultString;
}

外部データを統合することで、EAはパラメータを最適化するタイミングと方法について、より情報に基づいた決定を下せる可能性が高まります。

10.3 クラウドベースの最適化

最適化タスクがより複雑になるにつれて、クラウドベースのソリューションはより強力で柔軟な最適化プロセスの可能性を提供します。

void CloudOptimize()
{
    string optimizationData = PrepareOptimizationData();
    string url = "https://your-cloud-service.com/optimize";
    string headers = "Content-Type: application/json\r\n";
    char post[], result[];
    string resultHeaders;
    
    StringToCharArray(optimizationData, post);
    
    int res = WebRequest("POST", url, headers, 30000, post, result, resultHeaders);
    
    if(res == -1)
    {
        Print("Error in WebRequest. Error code =", GetLastError());
        return;
    }
    
    string optimizationResult = CharArrayToString(result);
    ApplyCloudOptimizationResult(optimizationResult);
}

このアプローチにより、ローカルマシンで実現可能なものよりも高い計算能力と、潜在的にさらに高度な最適化アルゴリズムを活用できるようになります。

効果的な自動最適化EAの開発は、継続的な改善と学習を必要とする継続的なプロセスです。改善のための1つの戦略は、EAのパフォーマンスを定期的に確認することです。この方法は、改良すべき領域を特定し、変化する市場状況でEAが最適なパフォーマンスを維持し続けることを保証するのに役立ちます。

void WeeklyPerformanceReview()
{
    datetime startOfWeek = iTime(_Symbol, PERIOD_W1, 0);
    double weeklyProfit = 0;
    int totalTrades = 0;
    
    for(int i = 0; i < HistoryDealsTotal(); i++)
    {
        ulong ticket = HistoryDealGetTicket(i);
        if(HistoryDealGetInteger(ticket, DEAL_TIME) >= startOfWeek)
        {
            weeklyProfit += HistoryDealGetDouble(ticket, DEAL_PROFIT);
            totalTrades++;
        }
    }
    
    Print("Weekly Performance: Profit = ", weeklyProfit, ", Trades = ", totalTrades);
}

これらのレビューを使用して、最適化プロセスの改善領域と潜在的な問題を特定します。

取引技術、市場の動向、規制について常に情報を得ることは不可欠です。アウトオブサンプルやフォワードテストを含む徹底的なテストが重要です。継続的な学習と監視が長期的な成功の鍵です。自動最適化は強力ですが、健全な取引原則とリスク管理を補完するものでなければなりません。好奇心と注意を怠らず、資本の保護を優先してください。

取引をお楽しみください。

自動最適化とアルゴリズム取引についての理解を深めたい方のために、以下の追加リソースをご紹介します。

  1. Building Reliable Trading Systems(Keith Fitschen著)
  2. Algorithmic Trading:Winning Strategies and Their Rationale(Ernie Chan著)
  3. Machine Learning for Algorithmic Trading(Stefan Jansen著)
  4. MQL5ドキュメント:MQL5ドキュメント
  5. Forex Factory Forum - Coding Forum:Forex Factory Forum
  6. Quantopian Lectures:Quantopian Lectures


11. EAコード例

以下は自動最適化EAの完全なコードです。このコードをMetaEditorにコピーし、MetaTrader 5で使用するためにコンパイルします。

//+------------------------------------------------------------------+
//|                 Auto-Optimizing Moving Average Crossover EA      |
//| Copyright 2024, Javier Santiago Gaston de Iriarte Cabrera        |
//|               https://www.mql5.com/ja/users/jsgaston/news        |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Javier Santiago Gaston de Iriarte Cabrera"
#property link      "https://www.mql5.com/ja/users/jsgaston/news"
#property version   "1.00"
#property strict

// Include necessary libraries
#include <Trade\Trade.mqh>
#include <Arrays\ArrayObj.mqh>

// Input parameters
input ENUM_MA_METHOD MA_Method = MODE_SMA; // Moving Average Method
input ENUM_APPLIED_PRICE Applied_Price = PRICE_CLOSE; // Applied Price
input double LotSize = 0.01;        // Lot Size
input int StopLoss = 100;           // Stop Loss in points
input int TakeProfit = 200;        // Take Profit in points
input int Initial_MA_Fast_Period = 10;  // Initial Fast Moving Average Period
input int Initial_MA_Slow_Period = 20;  // Initial Slow Moving Average Period

// Optimization parameters
input bool AutoOptimize = true;    // Enable Auto Optimization
input int OptimizationPeriod = 5000; // Number of ticks between optimizations
input int MinDataPoints = 1000;    // Minimum number of data points for optimization

// Global variables
CTrade trade;
int fastMA_Handle, slowMA_Handle;
double fastMA[], slowMA[];
int tickCount = 0;
CArrayObj optimizationResults;
int MA_Fast_Period, MA_Slow_Period;

// Optimization ranges
const int MA_Fast_Min = 5, MA_Fast_Max = 50, MA_Fast_Step = 1;
const int MA_Slow_Min = 10, MA_Slow_Max = 100, MA_Slow_Step = 1;

// Class to hold optimization results
class OptimizationResult : public CObject
{
public:
    int fastPeriod;
    int slowPeriod;
    double profit;
};

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    MA_Fast_Period = Initial_MA_Fast_Period;
    MA_Slow_Period = Initial_MA_Slow_Period;

    // Initialize MA handles
    fastMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Fast_Period, 0, MA_Method, Applied_Price);
    slowMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Slow_Period, 0, MA_Method, Applied_Price);
    
    if(fastMA_Handle == INVALID_HANDLE || slowMA_Handle == INVALID_HANDLE)
    {
        Print("Failed to create MA indicators");
        return INIT_FAILED;
    }
    
    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    // Release MA handles
    IndicatorRelease(fastMA_Handle);
    IndicatorRelease(slowMA_Handle);
    
    // Clean up optimization results
    optimizationResults.Clear();
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    // Check if we have enough bars to calculate MAs
    if(Bars(_Symbol, PERIOD_CURRENT) < MA_Slow_Period) return;
    
    // Copy MA values
    if(CopyBuffer(fastMA_Handle, 0, 0, 2, fastMA) != 2) return;
    if(CopyBuffer(slowMA_Handle, 0, 0, 2, slowMA) != 2) return;
    
    // Auto Optimization
    if(AutoOptimize && ++tickCount >= OptimizationPeriod)
    {
        Optimize();
        tickCount = 0;
    }
    
    // Trading logic
    if(fastMA[1] <= slowMA[1] && fastMA[0] > slowMA[0])
    {
        // Open buy position
        double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
        trade.Buy(LotSize, _Symbol, ask, ask - StopLoss * _Point, ask + TakeProfit * _Point);
    }
    else if(fastMA[1] >= slowMA[1] && fastMA[0] < slowMA[0])
    {
        // Open sell position
        double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
        trade.Sell(LotSize, _Symbol, bid, bid + StopLoss * _Point, bid - TakeProfit * _Point);
    }
}

//+------------------------------------------------------------------+
//| Optimization function                                            |
//+------------------------------------------------------------------+
void Optimize()
{
    Print("Starting optimization...");
    
    optimizationResults.Clear();
    
    // Loop through all combinations of MA periods
    for(int fastPeriod = MA_Fast_Min; fastPeriod <= MA_Fast_Max; fastPeriod += MA_Fast_Step)
    {
        for(int slowPeriod = MA_Slow_Min; slowPeriod <= MA_Slow_Max; slowPeriod += MA_Slow_Step)
        {
            if(slowPeriod <= fastPeriod) continue; // Slow period should be greater than fast period
            
            double profit = TestParameters(fastPeriod, slowPeriod);
            
            OptimizationResult* result = new OptimizationResult();
            result.fastPeriod = fastPeriod;
            result.slowPeriod = slowPeriod;
            result.profit = profit;
            
            optimizationResults.Add(result);
        }
    }
    
    // Find the best result
    OptimizationResult* bestResult = NULL;
    for(int i = 0; i < optimizationResults.Total(); i++)
    {
        OptimizationResult* currentResult = optimizationResults.At(i);
        if(bestResult == NULL || currentResult.profit > bestResult.profit)
        {
            bestResult = currentResult;
        }
    }
    
    if(bestResult != NULL)
    {
        // Update the EA parameters
        MA_Fast_Period = bestResult.fastPeriod;
        MA_Slow_Period = bestResult.slowPeriod;
        
        // Update indicator handles
        IndicatorRelease(fastMA_Handle);
        IndicatorRelease(slowMA_Handle);
        fastMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Fast_Period, 0, MA_Method, Applied_Price);
        slowMA_Handle = iMA(_Symbol, PERIOD_CURRENT, MA_Slow_Period, 0, MA_Method, Applied_Price);
        
        Print("Optimization complete. New parameters: Fast MA = ", MA_Fast_Period, ", Slow MA = ", MA_Slow_Period);
    }
    else
    {
        Print("Optimization failed to find better parameters.");
    }
}

//+------------------------------------------------------------------+
//| Test a set of parameters                                         |
//+------------------------------------------------------------------+
double TestParameters(int fastPeriod, int slowPeriod)
{
    int maFast = iMA(_Symbol, PERIOD_CURRENT, fastPeriod, 0, MA_Method, Applied_Price);
    int maSlow = iMA(_Symbol, PERIOD_CURRENT, slowPeriod, 0, MA_Method, Applied_Price);
    
    if(maFast == INVALID_HANDLE || maSlow == INVALID_HANDLE)
    {
        Print("Failed to create MA indicators for testing");
        return -DBL_MAX;
    }
    
    double fastBuffer[], slowBuffer[];
    ArraySetAsSeries(fastBuffer, true);
    ArraySetAsSeries(slowBuffer, true);
    
    int copied = CopyBuffer(maFast, 0, 0, MinDataPoints, fastBuffer);
    copied = MathMin(copied, CopyBuffer(maSlow, 0, 0, MinDataPoints, slowBuffer));
    
    if(copied < MinDataPoints)
    {
        Print("Not enough data for testing");
        return -DBL_MAX;
    }
    
    double Close[], Open[];
    ArraySetAsSeries(Close, true);
    ArraySetAsSeries(Open, true);
    copied = CopyClose(_Symbol, PERIOD_CURRENT, 0, copied, Close);
    copied = MathMin(copied, CopyOpen(_Symbol, PERIOD_CURRENT, 0, copied, Open));
    
    double profit = 0;
    for(int i = 1; i < copied; i++)
    {
        if(fastBuffer[i] > slowBuffer[i] && fastBuffer[i-1] <= slowBuffer[i-1])
        {
            // Buy signal
            profit += Close[i-1] - Open[i];
        }
        else if(fastBuffer[i] < slowBuffer[i] && fastBuffer[i-1] >= slowBuffer[i-1])
        {
            // Sell signal
            profit += Open[i] - Close[i-1];
        }
    }
    
    IndicatorRelease(maFast);
    IndicatorRelease(maSlow);
    
    return profit;
}

//+------------------------------------------------------------------+
//| Custom function to log important events                          |
//+------------------------------------------------------------------+
void Log(string message)
{
    Print(TimeToString(TimeCurrent()) + ": " + message);
    
    int handle = FileOpen("EA_Log.txt", FILE_WRITE|FILE_READ|FILE_TXT);
    if(handle != INVALID_HANDLE)
    {
        FileSeek(handle, 0, SEEK_END);
        FileWriteString(handle, TimeToString(TimeCurrent()) + ": " + message + "\n");
        FileClose(handle);
    }
}

EAの使い方

  1. コード全体をMetaEditorの新規ファイルにコピーします。
  2. ファイルを拡張子.mq5で保存します(例:AutoOptimizingMA.mq5)。
  3. [コンパイル]ボタンをクリックするか、F7キーを押してEAをコンパイルします。
  4. MetaTrader 5で、コンパイルしたEAをチャート上にドラッグします。
  5. EAの設定ウィンドウで、必要に応じて入力パラメーターを調整します。
  6. 自動売買を有効にし、EAを実行させます。

このEAの主な特徴

  1. 移動平均クロスオーバー戦略:このEAは、基本的な移動平均クロスオーバー戦略を使用して取引を決定します。
  2. 自動最適化:EAは、最近の市場データに基づいてパラメータ(高速MA期間と低速MA期間)を自動的に最適化することができます。
  3. カスタマイズ可能な入力:ユーザーは、ロットサイズ、ストップロス、テイクプロフィット、最適化設定を含む様々なパラメータを調整することができます。
  4. パフォーマンスロギング:EAには、重要なイベントやパラメータの変更を追跡するロギング機能があります。

重要な注意事項

  • このEAは教育的な例として提供されたものであり、徹底的なテストとカスタマイズなしにライブ取引に使用しないでください。特にVPSやローカルマシンで実行する場合は、システムリソースに注意してください。 
  • 実取引を検討する前に、必ずデモ環境でEAを十分にテストしてください。
  • 過去の実績は将来の結果を保証するものではない。市場環境は変化する可能性があり、EAのパフォーマンスに影響を与える可能性があります。

このEAを使用することで、自動最適化が実際にどのように機能するかを調べることができ、変化する市場環境に対する取引戦略の適応性を向上させる可能性があります。そのパフォーマンスを継続的に監視し、必要に応じて調整することを忘れないでください。

設定


入力

グラフ


バックテスト

ディープラーニングやRSIなど、考えられる限りの条件を組み合わせて注文に追加することで、さらに良い結果を得られる可能性があります。

アルゴリズム取引の世界は広大で、絶えず進化しています。このガイドが、EAの自動最適化への旅の出発点となることを願っています。経験を積み、理解を深めていく中で、取引システムを改良・改善するための新しいテクニックやアプローチがきっと見つかるでしょう。

成功をお祈りしています。あなたの取引が素晴らしい利益をもたらすことを願っています。

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

添付されたファイル |
MQL5で取引管理者パネルを作成する(第3回):ビジュアルスタイリングによるGUIの強化(I) MQL5で取引管理者パネルを作成する(第3回):ビジュアルスタイリングによるGUIの強化(I)
この記事では、MQL5を使用して、取引管理パネルのグラフィカルユーザーインターフェイス(GUI)を視覚的にスタイル設定することに焦点を当てます。MQL5で利用できるさまざまなテクニックと機能について説明します。これらのテクニックと機能により、インターフェイスのカスタマイズと最適化が可能になり、魅力的な外観を維持しながらトレーダーのニーズを満たすことができます。
ディープラーニングを用いたCNA(因果ネットワーク分析)、SMOC(確率モデル最適制御)、ナッシュゲーム理論の例 ディープラーニングを用いたCNA(因果ネットワーク分析)、SMOC(確率モデル最適制御)、ナッシュゲーム理論の例
以前の記事で発表されたこれら3つの例にディープラーニング(DL)を加え、以前の結果と比較します。目的は、他のEAにディープラーニングを追加する方法を学ぶことです。
PSAR、平均足、ディープラーニングを組み合わせて取引に活用する PSAR、平均足、ディープラーニングを組み合わせて取引に活用する
このプロジェクトでは、ディープラーニングとテクニカル分析の融合を探求し、FXの取引戦略を検証します。EUR/USDの動きを予測するために、PSAR、SMA、RSIのような伝統的な指標とともにONNXモデルを採用し、迅速な実験のためにPythonスクリプトを使用します。MetaTrader 5のスクリプトは、この戦略をライブ環境に導入し、ヒストリカルデータとテクニカル分析を使用して、情報に基づいた取引決定をおこないます。バックテストの結果は、積極的な利益追求よりもリスク管理と着実な成長に重点を置いた、慎重かつ一貫したアプローチを示しています。
MQL5-Telegram統合エキスパートアドバイザーの作成(第6回):レスポンシブなインラインボタンの追加 MQL5-Telegram統合エキスパートアドバイザーの作成(第6回):レスポンシブなインラインボタンの追加
この記事では、インタラクティブなインラインボタンをMQL5エキスパートアドバイザー(EA)に統合し、Telegram経由でリアルタイムにコントロールできるようにします。各ボタンを押すたびに特定のアクションがトリガーされ、ユーザーにレスポンスが返されます。また、Telegramメッセージやコールバッククエリを効率的に処理するための関数もモジュール化します。