見出し画像

各通貨ペア時間毎のボラを測定する

EAを作る際に避けて通れない、『ボラ』への配慮
EA作成を行う上で、パラメータの最適化範囲をあらかた知っておいてから進めた方が効率的じゃね?ということで作成

今回はATR(9)の測定を行っていますが、皆さんが開発に利用しているインジケータに合わせて測定してみると面白いかもしれません


紹介するEAについて

・過去9本のATRを測定する
・各時間ごとに、0~20_point,20~40_point,....,480~500_pointの結果を入れる2次変数を作る
・新しいTickが発生したタイミングで、足が確定した1つ前ATRを取り込み、その値が10~20_pointであれば10~20_pointの変数にプラス1する
・途中経過では、実際の数を表示
・テスト完了時には、パーセンテージに変換したものを表示する

// --- 定義部分 ---
int ATR_Buckets[24][25];  // 0~23時台、0~500_pointを20_pointごとに分けた25個のバケット
int ATR_Period = 9;       // ATRの期間
datetime last_tick_time = 0;  // 最後に処理されたティック時間
int atr_handle;           // ATRインジケータのハンドル

// OnInit関数
int OnInit()
{
    // バケットの初期化
    ArrayInitialize(ATR_Buckets, 0);
    
    // 初回ティック時間の初期化
    last_tick_time = iTime(_Symbol, _Period, 0);

    // ATRインジケータのハンドルを取得
    atr_handle = iATR(NULL, 0, ATR_Period);
    if (atr_handle == INVALID_HANDLE)
    {
        Print("Failed to initialize ATR indicator");
        return(INIT_FAILED);
    }
    
    return(INIT_SUCCEEDED);
}

// 新しいティックが発生したかどうかをチェックする関数
bool isNewTick()
{
    // 現在のティック時間が前回のティック時間と異なる場合
    if (last_tick_time < iTime(_Symbol, _Period, 0))
    {
        last_tick_time = iTime(_Symbol, _Period, 0);  // 現在のティック時間を保存
        return true;  // 新しいティックが発生したことを示す
    }
    
    return false;  // ティックが同じなら新しいティックは発生していない
}

// OnTick関数
void OnTick()
{
    // 新しいティックが発生した場合のみ処理を行う
    if (isNewTick())
    {
        double atr_values[1]; // ATR値を格納する配列
        if (CopyBuffer(atr_handle, 0, 1, 1, atr_values) > 0)
        {
            double atr = atr_values[0]; // ATR値を取得
            int atr_points = (int)(atr / _Point);  // ATRをポイントに変換
            
            // 現在の時間を取得
            MqlDateTime time_struct;
            TimeToStruct(TimeCurrent(), time_struct);
            int current_hour = time_struct.hour;
            
            // ATRが0~500ポイントの範囲内であれば対応するバケットの数値を1増やす
            if (atr_points >= 0 && atr_points < 500)
            {
                int bucket_index = atr_points / 20;
                ATR_Buckets[current_hour][bucket_index]++;
                PrintATRResults();
                Print("____");
            }
        }
    }
}

// 集計結果を表示する関数
void PrintATRResults()
{
    string header = "Rng/Hr  ";  // ヘッダー部分の初期化
    
    // ヘッダー行の作成(Hour 0 ~ 23)
    for (int hour = 0; hour < 24; hour++)
    {
        header += StringFormat("%4d  ", hour);
    }
    Print(header);  // ヘッダーを表示
    
    // 各範囲ごとのATR値の集計結果を表示
    for (int i = 0; i < 25; i++)
    {
        string row = StringFormat("%4d-  ", i * 20);
        
        for (int hour = 0; hour < 24; hour++)
        {
            row += StringFormat("%5d ", ATR_Buckets[hour][i]);
        }
        Print(row);  // 各範囲の行を表示
    }
}

void PrintATRPercentage()
{
    string header = "Rng/Hr  ";  // ヘッダー部分の初期化
    
    // ヘッダー行の作成(Hour 0 ~ 23)
    for (int hour = 0; hour < 24; hour++)
    {
        header += StringFormat("%4d  ", hour);
    }
    Print(header);  // ヘッダーを表示
    
    // 各時間帯の総カウント数を計算
    int total_counts[24] = {0};
    for (int hour = 0; hour < 24; hour++)
    {
        for (int i = 0; i < 25; i++)
        {
            total_counts[hour] += ATR_Buckets[hour][i];
        }
    }
    
    // 各範囲ごとのパーセンテージを表示
    for (int i = 0; i < 25; i++)
    {
        string row = StringFormat("%4d-  ", i * 20);
        
        for (int hour = 0; hour < 24; hour++)
        {
            double percentage = (double)ATR_Buckets[hour][i] / total_counts[hour] * 100.0;
            row += StringFormat("%5.1f ", percentage);
        }
        Print(row);  // 各範囲の行を表示
    }
}

// OnTester関数
double OnTester()
{
    PrintATRPercentage();  // 集計結果を表示する関数を呼び出す
    return 0.0;
}


実行結果サンプル
2018年1月4日~2024年8月20日
USDJPY M15 1分足OHLC

USDJPY_時間vsATR9_15min累積
パーセンテージ


MQL5コード一覧はコチラ

https://note.com/noway_pway/n/na50e47a51645

この記事が気に入ったらサポートをしてみませんか?