English Русский Español Português
preview
アルゴリズム取引戦略:AIで金市場の頂点を目指す

アルゴリズム取引戦略:AIで金市場の頂点を目指す

MetaTrader 5トレーディングシステム |
32 12
dmitrievsky
削除済み

はじめに

機械学習手法が取引分野で有効であることが広く認識されるようになり、さまざまなアルゴリズムが生まれました。これらのアルゴリズムは、同じタスクに対して同様の性能を発揮しますが、基本的な仕組みは異なります。本記事でも金市場における一方向型のトレンドフォロー戦略を構築しますが、今回はクラスタリングアルゴリズムを使用します。

  • 前回の記事では、同様の金のトレンド戦略を作成するための2種類の因果推論アルゴリズムが紹介されました。
  • 時系列クラスタリングに関する記事では、取引タスクにおけるクラスタリングのさまざまな方法について解説しています。
  • さらに、クラスタリングアルゴリズムを用いた平均回帰戦略の作成事例も公開されました。
  • 今回のクラスタリングに基づくトレンドフォロー型取引システムの開発は、このアプローチの有用性をさらに明らかにしています。

このように、時系列データを多角的に分析・予測する重要なアプローチを考慮することで、従来の金融時系列の分析と予測のみを基にした取引システム作成法と比較し、利点や欠点を評価することが可能です。場合によっては、これらのアルゴリズムは非常に高い効果を発揮し、作成速度や生成される取引システムの品質の両面で、従来手法を上回ることもあります。

本記事では、一方向性取引戦略に焦点を当てます。この場合、アルゴリズムは買いまたは売りのいずれか一方向のポジションのみを保有します。基本アルゴリズムとしてCatBoostとK-Meansを使用します。CatBoostは、取引方向を判定する二値分類モデルとして機能します。一方、K-Meansは、前処理フェーズで市場のモードを判定するために使用されます。


作業準備とモジュールのインポート

import math
import pandas as pd
from datetime import datetime
from catboost import CatBoostClassifier

from sklearn.model_selection import train_test_split
from sklearn.cluster import KMeans

from bots.botlibs.labeling_lib import *
from bots.botlibs.tester_lib import tester_one_direction
from bots.botlibs.export_lib import export_model_to_ONNX

import time

このコードでは、信頼性があり、公開されている検証済みのパッケージのみを使用しています。

  • Pandas:データテーブル(DataFrame)の操作を担当
  • Scikit-learn:前処理や機械学習の各種機能を提供しており、クラスタリングアルゴリズムも含む
  • CatBoost:Yandexが提供する強力な勾配ブースティングアルゴリズム

さらに、作成した個別モジュールもインポートしています。

  • labeling_lib:取引にラベルを付与するためのサンプラー関数を含む
  • tester_lib:機械学習ベースの戦略をテストするためのモジュール
  • export_lib:学習済みモデルをONNX形式でMetaTrader 5にエクスポートするためのモジュール


データの取得と特徴量の作成

def get_prices() -> pd.DataFrame:
    p = pd.read_csv('files/'+hyper_params['symbol']+'.csv', sep='\s+')
    pFixed = pd.DataFrame(columns=['time', 'close'])
    pFixed['time'] = p['<DATE>'] + ' ' + p['<TIME>']
    pFixed['time'] = pd.to_datetime(pFixed['time'], format='mixed')
    pFixed['close'] = p['<CLOSE>']
    pFixed.set_index('time', inplace=True)
    pFixed.index = pd.to_datetime(pFixed.index, unit='s')
    return pFixed.dropna()

このコードでは、ファイルから価格データ(クオート)を読み込む処理を実装しており、複数のデータソースからの取得を容易にしています。この際、終値のみを使用します。取得したデータに基づいて特徴量を生成します。

def get_features(data: pd.DataFrame) -> pd.DataFrame:
    pFixed = data.copy()
    pFixedC = data.copy()
    count = 0

    for i in hyper_params['periods']:
        pFixed[str(count)] = pFixedC.rolling(i).std()
        count += 1
    
    for i in hyper_params['periods_meta']:
        pFixed[str(count)+'meta_feature'] = pFixedC.rolling(i).std()
        count += 1

特徴量は2つのグループに分けられます。

  1. 基本モデルの学習に用いる主要特徴量:取引の方向(売り/買い)を予測するモデルの学習に使用します。
  2. クラスタリング用のメタ特徴量(追加特徴量):元データを市場モード(クラスタ)に分類するために使用します。

この例では、ボラティリティ(一定期間の価格の標準偏差)を特徴量として使用しています。ただし、今後は移動平均や分布の歪度など、他の特徴量もテストする予定です。


市場モードのクラスタリング

def clustering(dataset, n_clusters: int) -> pd.DataFrame:
    data = dataset[(dataset.index < hyper_params['forward']) & (dataset.index > hyper_params['backward'])].copy()
    meta_X = data.loc[:, data.columns.str.contains('meta_feature')]
    data['clusters'] = KMeans(n_clusters=n_clusters).fit(meta_X).labels_
    return data

この関数は、価格データと特徴量を持つDataFrameを受け取り、追加のメタ特徴量を用いて指定された数のクラスタにクラスタリングします(通常は10程度のクラスタ数)。クラスタリングにはK-Meansアルゴリズムを使用します。その後、DataFrameの各行にクラスタラベルが付与されます。最終的に、clusters列を追加したDataFrameが返されます。


分類器を学習させる関数

def fit_final_models(clustered, meta) -> list:
    # features for model\meta models. We learn main model only on filtered labels 
    X, X_meta = clustered[clustered.columns[:-1]], meta[meta.columns[:-1]]
    X = X.loc[:, ~X.columns.str.contains('meta_feature')]
    X_meta = X_meta.loc[:, X_meta.columns.str.contains('meta_feature')]
    
    # labels for model\meta models
    y = clustered['labels']
    y_meta = meta['clusters']
    
    y = y.astype('int16')
    y_meta = y_meta.astype('int16')

    # train\test split
    train_X, test_X, train_y, test_y = train_test_split(
        X, y, train_size=0.7, test_size=0.3, shuffle=True)
    
    train_X_m, test_X_m, train_y_m, test_y_m = train_test_split(
        X_meta, y_meta, train_size=0.7, test_size=0.3, shuffle=True)


    # learn main model with train and validation subsets
    model = CatBoostClassifier(iterations=500,
                               custom_loss=['Accuracy'],
                               eval_metric='Accuracy',
                               verbose=False,
                               use_best_model=True,
                               task_type='CPU',
                               thread_count=-1)
    model.fit(train_X, train_y, eval_set=(test_X, test_y),
              early_stopping_rounds=25, plot=False)
    
    # learn meta model with train and validation subsets
    meta_model = CatBoostClassifier(iterations=300,
                                    custom_loss=['F1'],
                                    eval_metric='F1',
                                    verbose=False,
                                    use_best_model=True,
                                    task_type='CPU',
                                    thread_count=-1)
    meta_model.fit(train_X_m, train_y_m, eval_set=(test_X_m, test_y_m),
              early_stopping_rounds=15, plot=False)

    
    R2 = test_model_one_direction([model, meta_model],
                                hyper_params['stop_loss'], 
                                hyper_params['take_profit'],
                                hyper_params['full forward'],
                                hyper_params['backward'],
                                hyper_params['markup'],
                                hyper_params['direction'],
                                plt=False)
    if math.isnan(R2):
        R2 = -1.0
        print('R2 is fixed to -1.0')
    print('R2: ' + str(R2))

    return [R2, model, meta_model]

学習には2つのモデルを使用します。1つ目は基本特徴量とラベルを用いて学習するモデル、2つ目はメタ特徴量とメタラベルを用いて学習するモデルです。1つ目のモデルでは、ラベルは取引の方向(Buy/Sell)です。2つ目のモデルでは、ラベルはクラスタ番号に基づき、データが対象クラスタに該当する場合は1、他のクラスタに該当する場合は0です。 

学習前に、データは70/30の割合で学習用データと検証用データに分割されます。これは、CatBoostアルゴリズムの過学習を防ぐためです。学習中に検証データの誤差が改善されなくなった時点で、早期終了がおこなわれます。その後、検証データ上で最小の予測誤差を持つモデルが選択されます。

モデルを学習させた後は、テスト関数に渡して、決定係数を用いてバランスカーブを評価します。これは、モデルを後でソートし、最適なモデルを選択するために必要なステップです。


モデルテスト関数

def test_model_one_direction( 
               result: list, 
               stop: float, 
               take: float, 
               forward: float, 
               backward: float, 
               markup: float,
               direction: str, 
               plt = False):
    
    pr_tst = get_features(get_prices())
    X = pr_tst[pr_tst.columns[1:]]
    X_meta = X.copy()
    X = X.loc[:, ~X.columns.str.contains('meta_feature')]
    X_meta = X_meta.loc[:, X_meta.columns.str.contains('meta_feature')]

    pr_tst['labels'] = result[0].predict_proba(X)[:,1]
    pr_tst['meta_labels'] = result[1].predict_proba(X_meta)[:,1]
    pr_tst['labels'] = pr_tst['labels'].apply(lambda x: 0.0 if x < 0.5 else 1.0)
    pr_tst['meta_labels'] = pr_tst['meta_labels'].apply(lambda x: 0.0 if x < 0.5 else 1.0)
    return tester_one_direction(pr_tst, stop, take, forward, backward, markup, direction, plt)

この関数は、学習済みの2つのモデル(メインモデルとメタモデル)およびカスタム戦略テスターでのテストに必要な残りのパラメータを受け取ります。その後、再び価格と特徴量を含むDataFrameを作成し、これをモデルに渡して予測をおこないます。得られた予測結果は、DataFrameのlabels列およびmeta_labels列に格納されます。

最後に、プラグインモジュールtester_lib.py内にあるカスタムテスター関数が呼び出されます。学習済みモデルを履歴データに対してテストし、決定係数による性能評価を返します。


取引のラベル生成関数

labeling_lib.pyモジュールには、指定方向の取引のみをラベル付けするサンプラーが含まれています。

@njit
def calculate_labels_one_direction(close_data, markup, min, max, direction):
    labels = []
    for i in range(len(close_data) - max):
        rand = random.randint(min, max)
        curr_pr = close_data[i]
        future_pr = close_data[i + rand]

        if direction == "sell":
            if (future_pr + markup) < curr_pr:
                labels.append(1.0)
            else:
                labels.append(0.0)
        if direction == "buy":
            if (future_pr - markup) > curr_pr:
                labels.append(1.0)
            else:
                labels.append(0.0)
    return labels

def get_labels_one_direction(dataset, markup, min = 1, max = 15, direction = 'buy') -> pd.DataFrame:
    close_data = dataset['close'].values
    labels = calculate_labels_one_direction(close_data, markup, min, max, direction)
    dataset = dataset.iloc[:len(labels)].copy()
    dataset['labels'] = labels
    dataset = dataset.dropna()
    return dataset


メイン学習ループ

# LEARNING LOOP
dataset = get_features(get_prices()) 	// getting prices and features
models = [] 				// making empty list of models

for i in range(1):							// the loop sets how many training attempts need to be completed
    start_time = time.time()
    data = clustering(dataset, n_clusters=hyper_params['n_clusters']) 	// adding cluster numbers to data
    sorted_clusters = data['clusters'].unique() 			// defining unique clusters
    sorted_clusters.sort() 						// sorting clusters in ascending order
    for clust in sorted_clusters: 					// loop over all clusters
        clustered_data = data[data['clusters'] == clust].copy()		// selecting data for single cluster
        if len(clustered_data) < 500:
            print('too few samples: {}'.format(len(clustered_data)))	// checking for sufficiency of training samples
            continue
    
        clustered_data = get_labels_one_direction(clustered_data,	// marking up trades for selected cluster
                                       markup=hyper_params['markup'],
                                       min=1,
                                       max=15,
                                       direction=hyper_params['direction'])
        
        print(f'Iteration: {i}, Cluster: {clust}')
        clustered_data = clustered_data.drop(['close', 'clusters'], axis=1)// deleting closing prices and cluster numbers

        meta_data = data.copy()	// creating data for meta-model
        meta_data['clusters'] = meta_data['clusters'].apply(lambda x: 1 if x == clust else 0) // marking up current cluster as "1"
        models.append(fit_final_models(clustered_data, meta_data.drop(['close'], axis=1))) // training models and adding them to list
    end_time = time.time()
    print("Execution time: ", end_time - start_time)

学習ループでは、これまでに説明したすべての関数が順番に使用されます。

  • 価格データ(クオート)をファイルからDataFrameに読み込み、特徴量を作成します。
  • 学習済みモデルを格納する空のリストを作成します。
  • 同じデータで複数回学習をおこない、モデルのランダムなばらつきの影響を抑えます。
  • メタ特徴量に基づいてクラスタリングをおこない、DataFrameにclusters列を追加します。
  • ループ内で、各クラスタごとにそのクラスタに属するデータのみを選択します。
  • 各クラスタのデータに対してラベル付けをおこない、メインモデル用のクラスラベルを作成します。
  • メタモデル用の追加データセットを作成し、対象クラスタを他のクラスタと区別するための学習に使用します。
  • これら2つのデータセットを学習関数に渡し、2つの分類器(メインモデルとメタモデル)を学習させます。
  • 学習済みモデルは、作成したリストに追加されます。


モデルの学習およびテストプロセス

アルゴリズムのハイパーパラメータ(全体設定)は、以下の辞書にまとめられています。

hyper_params = {
    'symbol': 'XAUUSD_H1',
    'export_path': '/drive_c/Program Files/MetaTrader 5/MQL5/Include/Mean reversion/',
    'model_number': 0,
    'markup': 0.2,
    'stop_loss':  10.000,
    'take_profit': 5.000,
    'periods': [i for i in range(5, 300, 30)],
    'periods_meta': [5],
    'backward': datetime(2020, 1, 1),
    'forward': datetime(2024, 1, 1),
    'full forward': datetime(2026, 1, 1),
    'direction': 'buy',
    'n_clusters': 10,
}

学習期間は2020年から2024年までとし、テスト期間は2024年初頭から現在までとします。

特に重要なのは、以下のパラメータを正しく設定することです。

  • markup - 0.2:XAUUSDにおける平均スプレッドを表します。スプレッドを小さくしすぎたり大きくしすぎたりすると、テスト結果が現実的でなくなる可能性があります。また、スリッページや手数料などの追加コストがある場合も、ここに含めます。
  • stop_loss:ポイント単位での銘柄のストップロス幅です。
  • take_profit:ポイント単位でのテイクプロフィット幅です。なお、ポジションはモデルのシグナルに反した場合だけでなく、ストップロスまたはテイクプロフィットに到達した場合にも決済されます。
  • periods:主要特徴量用の期間リストです。一般的には、5から開始し、30刻みで約10個の期間を設定すれば十分です。
  • periods_meta:メタ特徴量用の期間リストです。市場モードを識別するために多数の特徴量は必要ありません。通常は、直近5本のバーに対する標準偏差など、1つの指標で十分です。
  • direction:今回は金市場に上昇トレンドが見られるため、「buy」のみを使用します。 
  • n_clusters:クラスタリングにおけるモード(クラスタ)の数です。通常は10を使用します。

標準偏差を使用した学習

まずは、特徴量として標準偏差のみを使用します。そのため、特徴量作成関数は次のようになります。

def get_features(data: pd.DataFrame) -> pd.DataFrame:
    pFixed = data.copy()
    pFixedC = data.copy()
    count = 0

    for i in hyper_params['periods']:
        pFixed[str(count)] = pFixedC.rolling(i).std()
        count += 1
    
    for i in hyper_params['periods_meta']:
        pFixed[str(count)+'meta_feature'] = pFixedC.rolling(i).std()
        count += 1

    return pFixed.dropna()

1回の学習ループを実行すると、以下のような情報が得られます。

Iteration: 0, Cluster: 0
R2: 0.989543793954197
Iteration: 0, Cluster: 1
R2: 0.9697821077241253
too few samples: 19
too few samples: 238
Iteration: 0, Cluster: 4
R2: 0.9852770333065658
Iteration: 0, Cluster: 5
R2: 0.7723040599270985
too few samples: 87
Iteration: 0, Cluster: 7
R2: 0.9970885055361235
Iteration: 0, Cluster: 8
R2: 0.9524980839809385
too few samples: 446
Execution time:  2.140070915222168

10個の市場モード(クラスタ)に対して、10個のモデルを学習する試みがおこなわれました。しかし、すべてのモードが有効だったわけではありません。いくつかのクラスタでは、学習サンプル(取引数)が少なすぎました。そのため、最小取引数のフィルタを通過できず、学習には使用されませんでした。

最も良い結果を示したのはクラスタ番号7で、R² = 0.99という非常に高い値を記録しました。これは、最良の取引モデル候補として非常に有望です。また、学習ループ全体の実行時間はわずか2秒でした。非常に高速であることが分かります。

モデルをソートした後、最良モデルをテストします。

図1:ソート後の最良モデルのテスト結果

次点のモデルも、取引回数が多く、非常に良好な結果を示しました。

図2:2位モデルのテスト結果

モデルの学習とテストが非常に高速であるため、ループを何度も再実行して、より高品質なモデルを探すことが可能です。たとえば、再度ループを実行してソートした結果、次のようなバリエーションが得られました。

図3:再学習後の最良モデルのテスト結果

移動平均と標準偏差を用いた学習

それでは特徴量を変更し、モデルのパフォーマンスがどのように変化するかを確認してみます。

def get_features(data: pd.DataFrame) -> pd.DataFrame:
    pFixed = data.copy()
    pFixedC = data.copy()
    count = 0

    for i in hyper_params['periods']:
        pFixed[str(count)] = pFixedC.rolling(i).mean()
        count += 1
    
    for i in hyper_params['periods_meta']:
        pFixed[str(count)+'meta_feature'] = pFixedC.rolling(i).std()
        count += 1

    return pFixed.dropna()

単純移動平均をメインの特徴量として使用し、標準偏差をメタ特徴量として使用します。

学習ループを開始し、最良のモデルを検討します。

Iteration: 0, Cluster: 0
R2: 0.9312180471969619
Iteration: 0, Cluster: 1
R2: 0.9839766532391275
too few samples: 101
Iteration: 0, Cluster: 3
R2: 0.9643925934007344
too few samples: 299
Iteration: 0, Cluster: 5
R2: 0.9960009821184868
too few samples: 19
Iteration: 0, Cluster: 7
R2: 0.9557947960449501
Iteration: 0, Cluster: 8
R2: 0.9747160963596306
Iteration: 0, Cluster: 9
R2: 0.5526910449937035
Execution time:  2.8627688884735107

テスターで最適なモデルは次のようになります。

図4:移動平均を用いた最良モデルのテスト結果

第2位のモデルも良好なパフォーマンスを示しています。

図5:移動平均を用いた第2位モデルのテスト結果

学習ループをさらに数回再実行した結果、より滑らかなバランス曲線を持つモデルが得られました。

図6:再学習後の最良モデルのテスト結果

今回は特徴量の数(期間リスト)は特に最適化していません。そのため、期間の組み合わせを変更することで、さらに多様なモデルを生成することが可能です。提示したスクリーンショットは、あくまでその一部のバリエーションを示したものです。


過学習との戦い

モデルが過度に複雑になると、汎化性能が低下することがあります。これは、バリデーションフェーズやアーリーストッピングをおこなっている場合でも起こり得ます。このような場合は、特徴量の数を減らす、モデルを単純化するといった対策を試すことができます。CatBoostアルゴリズムにおける「モデルの複雑さ」とは、主に反復回数、つまり逐次的に構築される決定木の本数を指します。fit_final_models()関数内で、以下の値を変更してみてください。

def fit_final_models(clustered, meta) -> list:
    # features for model\meta models. We learn main model only on filtered labels 
    X, X_meta = clustered[clustered.columns[:-1]], meta[meta.columns[:-1]]
    X = X.loc[:, ~X.columns.str.contains('meta_feature')]
    X_meta = X_meta.loc[:, X_meta.columns.str.contains('meta_feature')]
    
    # labels for model\meta models
    y = clustered['labels']
    y_meta = meta['clusters']
    
    y = y.astype('int16')
    y_meta = y_meta.astype('int16')

    # train\test split
    train_X, test_X, train_y, test_y = train_test_split(
        X, y, train_size=0.8, test_size=0.2, shuffle=True)
    
    train_X_m, test_X_m, train_y_m, test_y_m = train_test_split(
        X_meta, y_meta, train_size=0.8, test_size=0.2, shuffle=True)


    # learn main model with train and validation subsets
    model = CatBoostClassifier(iterations=100,
                               custom_loss=['Accuracy'],
                               eval_metric='Accuracy',
                               verbose=False,
                               use_best_model=True,
                               task_type='CPU',
                               thread_count=-1)
    model.fit(train_X, train_y, eval_set=(test_X, test_y),
              early_stopping_rounds=15, plot=False)

ここでは、iterationsを100に削減し、early_stopping_roundsを15に設定しています。これにより、より単純なモデルを構築できるようになります。

図7:複雑さを抑えたモデルのテスト結果


MetaTrader 5ターミナルへのモデルのエクスポート

export_lib()モジュールexport_model_to_ONNX()関数には、次の文字列が含まれています。

# get features
    code += 'void fill_arays' + symbol + '_' + str(model_number) + '( double &features[]) {\n'
    code += '   double pr[], ret[];\n'
    code += '   ArrayResize(ret, 1);\n'
    code += '   for(int i=ArraySize(Periods'+ symbol + '_' + str(model_number) + ')-1; i>=0; i--) {\n'
    code += '       CopyClose(NULL,PERIOD_H1,1,Periods' + symbol + '_' + str(model_number) + '[i],pr);\n'
    code += '       ret[0] = MathMean(pr);\n'
    code += '       ArrayInsert(features, ret, ArraySize(features), 0, WHOLE_ARRAY); }\n'
    code += '   ArraySetAsSeries(features, true);\n'
    code += '}\n\n'

    # get features
    code += 'void fill_arays_m' + symbol + '_' + str(model_number) + '( double &features[]) {\n'
    code += '   double pr[], ret[];\n'
    code += '   ArrayResize(ret, 1);\n'
    code += '   for(int i=ArraySize(Periods_m' + symbol + '_' + str(model_number) + ')-1; i>=0; i--) {\n'
    code += '       CopyClose(NULL,PERIOD_H1,1,Periods_m' + symbol + '_' + str(model_number) + '[i],pr);\n'
    code += '       ret[0] = MathSkewness(pr);\n'
    code += '       ArrayInsert(features, ret, ArraySize(features), 0, WHOLE_ARRAY); }\n'
    code += '   ArraySetAsSeries(features, true);\n'
    code += '}\n\n'

ハイライトされている行は、MQL5コード内で特徴量を計算する部分に対応しています。Pythonスクリプトのget_features()関数で前述のように特徴量を変更した場合は、このMQL5コード内の計算も必ず変更する必要があります。あるいは、すでにエクスポート済みの.mqhファイル内で修正しても構いません。

たとえば、エクスポートされたXAUUSD_H1 ONNX include 0.mqhファイルでは、次の部分を修正します。

#include <Math\Stat\Math.mqh>
#resource "catmodel XAUUSD_H1 0.onnx" as uchar ExtModel_XAUUSD_H1_0[]
#resource "catmodel_m XAUUSD_H1 0.onnx" as uchar ExtModel2_XAUUSD_H1_0[]

int PeriodsXAUUSD_H1_0[10] = {5,35,65,95,125,155,185,215,245,275};
int Periods_mXAUUSD_H1_0[1] = {5};

void fill_araysXAUUSD_H1_0( double &features[]) {
   double pr[], ret[];
   ArrayResize(ret, 1);
   for(int i=ArraySize(PeriodsXAUUSD_H1_0)-1; i>=0; i--) {
       CopyClose(NULL,PERIOD_H1,1,PeriodsXAUUSD_H1_0[i],pr);
       ret[0] = MathStandardDeviation(pr);
       // ret[0] = MathMean(pr);
       ArrayInsert(features, ret, ArraySize(features), 0, WHOLE_ARRAY); }
   ArraySetAsSeries(features, true);
}

void fill_arays_mXAUUSD_H1_0( double &features[]) {
   double pr[], ret[];
   ArrayResize(ret, 1);
   for(int i=ArraySize(Periods_mXAUUSD_H1_0)-1; i>=0; i--) {
       CopyClose(NULL,PERIOD_H1,1,Periods_mXAUUSD_H1_0[i],pr);
       ret[0] = MathStandardDeviation(pr);
       ArrayInsert(features, ret, ArraySize(features), 0, WHOLE_ARRAY); }
   ArraySetAsSeries(features, true);
}

現在のコードでは、get_features()関数で標準偏差のみを使用していた場合に対応するようになっています。移動平均を使用している場合は、MathStandardDeviation()をMathMean()に置き換えてください。

コンパイル後、すでにボットをMetaTrader 5上でテストできます。

図8:学習+フォワード期間でのテスト結果

図9:フォワード期間のみでのテスト結果


結論

本記事では、クラスタリングに基づく一方向トレンド戦略の別の構築方法を示しました。このアプローチの主な特徴は、直感的であることと学習速度が非常に速いことです。得られるモデルの品質は、前回の記事で紹介した手法と同等レベルです。

 Python files.zipアーカイブには、以下のPythonでの開発用のファイルが含まれています。

ファイル名 説明
one direction clusters.py 
学習モデルのメインスクリプト
labeling_lib.py
ラベル付けロジックを更新したモジュール
tester_lib.py
機械学習ベース戦略用に更新されたカスタムテスター
export_lib.py モデルをターミナルにエクスポートするモジュール
XAUUSD_H1.csv
MetaTrader 5ターミナルからエクスポートした価格データファイル

 MQL5 files.zipアーカイブには、MetaTrader 5用のファイルが含まれています。

ファイル名 説明
one direction clusters.ex5
記事で作成したボットのコンパイル済みファイル
one direction clusters.mq5
記事のボットのソースコード
Include//Trend following(フォルダ)
ONNXモデルおよびボット接続用ヘッダファイルの配置フォルダ

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

添付されたファイル |
MQL5_files.zip (103.29 KB)
Python_files.zip (547.58 KB)
最後のコメント | ディスカッションに移動 (12)
Aliaksandr Kazunka
Aliaksandr Kazunka | 26 5月 2025 において 12:01
つまり、R 2は修正指数であり、その効率はpipsの利益に基づいています。ドローダウンやその他のパフォーマンス指標はどうでしょうか?トレーニングで90%以上、テストで85%以上の結果を出すモデルがあれば、その指標は印象的な数字になるでしょう。MT5で何度テスターを実行しても、履歴で利益を得たことがありません。入金は途絶えています。Pythonのテスターでは0.97-0.98の利益を出しているにもかかわらずです。
削除済み | 26 5月 2025 において 12:17
sportoman #:
つまり、R2は修正指数であり、その効率はpipsの利益に基づいています。ドローダウンやその他のパフォーマンス指標はどうでしょうか?トレーニングで90%以上、テストで85%以上の結果を出すモデルがあれば、その指標は印象的な数字になるでしょう。MT5で何度テスターを実行しても、履歴で利益を得たことがありません。入金は途絶えています。Pythonのテスターでは0.97-0.98の利益を出しているにもかかわらずです。

これがCVと何の関係があるのか理解できません。

これらの戦略はすべて、非定常相場の履歴のみに基づいているため、証明力が低い。しかし、トレンドを捉えることはできる。

履歴をダブルチェックしても、トレンドが変われば確率は上がらない。つまり、歴史に基づいて将来について何かを証明することはできず、利用可能なデータに基づいてモデルがどの程度一般化できるかを推定することしかできない。そのためのテスト期間がある。

非定常系列のモデルをテストする新しい効率的な方法がすでに発明されていたら、ぜひ教えてください :).
削除済み | 26 5月 2025 において 13:00
平均回帰戦略に関する記事もある。そこでは、時系列はほとんど常に平均に戻るという、より強力な仮定がなされている。変化するトレンドとは異なります。
Vladimir Perervenko
Vladimir Perervenko | 29 5月 2025 において 08:47

では、AIはどこにいるのか?キャットバストはこのレベルまでアップグレードしたのか?それとも、観客をおびき寄せるためのよくあるマーケティングのトリックなのだろうか?

私はこの奇妙な機能に、異なる著者による最近のいくつかの出版物で気づいている。

キャットバスト以外にまともなモデルはいないのだろうか?

削除済み | 29 5月 2025 において 09:19
Vladimir Perervenko #:

では、AIはどこにいるのか?キャットバストはこのレベルまでアップグレードしたのか?それとも、これは観客をおびき寄せるためのよくあるマーケティング・ギミックなのか?

私はこの奇妙な機能に、異なる著者による最近のいくつかの出版物で気づいた。

catbust以外にまともなモデルはないのだろうか?

クリックベイト(一般的な略語)。私はこの言葉の支持者ではまったくない。

人々はMOを "AI "と呼ぶことに慣れている。それにTCは、クラスタリングや分類など、さまざまなMOアルゴリズムの複合体だ。
EAのサンプル EAのサンプル
一般的なMACDを使ったEAを例として、MQL4開発の原則を紹介します。
ゴールドを例にした一方向トレンド取引における機械学習の考察 ゴールドを例にした一方向トレンド取引における機械学習の考察
この記事では、選択した方向(買いまたは売り)のみで取引をおこなうアプローチについて説明します。この目的のために、因果推論と機械学習の手法を使用します。
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法 エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
この記事では、MT4において複数のEAの衝突をさける方法を扱います。ターミナルの操作、MQL4の基本的な使い方がわかる人にとって、役に立つでしょう。
初級から中級まで:構造体(V) 初級から中級まで:構造体(V)
本記事では、構造体をどのようにオーバーロード(拡張)するかについて探っていきます。特に初めて目にする方にとっては、最初は理解するのがかなり難しいかもしれません。より複雑で高度なトピックに踏み込む前に、これらの概念をしっかりと理解しておくことが非常に重要です。