English Русский 中文 Español Deutsch
preview
金融モデリングにおける合成データのための敵対的生成ネットワーク(GAN)(第2回):テスト用の合成シンボルの作成

金融モデリングにおける合成データのための敵対的生成ネットワーク(GAN)(第2回):テスト用の合成シンボルの作成

MetaTrader 5機械学習 |
123 0
LiviaObongo
LiviaObongo

はじめに

金融モデリングにおいて、トレーダーは大きな課題に直面しています。それは、利用可能なデータが極めて限られているという点です。この制約により、特に暴落、高ボラティリティ、または長期にわたる市場の持ち合い局面がデータセット内に十分に表現されていない場合、取引手法の構築や評価が困難になります。そのため、こうした戦略を用いる際、現実の市場環境においてパフォーマンスを一般化できるほど多様で包括的なデータが得られることは稀です。さらに、金融市場の構造は地政学的変化や経済政策の変更など、さまざまな要因の影響を受けます。履歴データだけでは、こうした多様な市場変数を完全に捉えることができず、トレーダーは過去のバックテストで好成績を残したアルゴリズムに依存せざるを得ませんが、それらは新たな、あるいは予測困難な市場局面には適応できない可能性があります。 

こうした課題を克服する手段として、人工データの活用が最良の解決策と考えられています。合成データは、非対称な市場状況も含め、現実的かつ多様な市場環境を提供することで、従来の履歴データを代替または補完することが可能です。これにより、ストレステストの精度やモデルの汎化能力が向上し、取引戦略の幅を広げ、強化することができます。 

第1回では、データセットの多様性とモデルの堅牢性を向上させました。第2回となる本記事では、金融データセットに対して適用される合成データ生成の手段として、GANを活用する方法を取り上げます。GANは、金融履歴の既存の数値記録をマッピングし、実際の市場動向をリアルに再現するデータを合成することに長けており、正確な予測を実現する、最先端の機械学習アプローチです。本記事では、GAN (Generative Adversarial Networks)などの高度な機械学習技術を用いて合成シンボルを生成する方法を解説し、シャピロ–ウィルク検定、t検定、ルビーン検定といった統計手法を通じて、それらが実際の市場データとどれほど類似しているかを検証します。データの整合性を確保することで、トレーダーは安心して合成データを自身の取引システムに活用できます。


金融モデリングにおけるGANの理解 

敵対的生成ネットワーク(GAN)は、実際のデータセットに酷似した人工データを生成することに特化した、機械学習分野における重要な進展です。GANは、GeneratorとDiscriminatorという2つのニューラルネットワークから構成され、競合的な学習プロセスを通じて機能します。Generatorは実際のデータと区別がつかないデータを生成し、Discriminatorはそれが本物か合成かを判別します。この相互作用により、両者は継続的に性能を向上させ、非常にリアルな合成データが生成されるのです。

金融モデリングの分野において、GANはデータの不足という根本的な問題に対処する有効な手段です。特に、市場関連の履歴データは、規制上の制約などにより入手が難しくなっています。また、市場の暴落や急激な価格変動といったイベントは発生頻度が低いため、学習データセットに十分に含まれておらず、さまざまな市場環境に対応できる戦略の汎用化を制限してしまいます。

GANは、実際のデータの特性を反映した合成金融データを生成することで、欠落している履歴情報を補完します。これにより、トレーダーや研究者は利用可能な情報を拡充でき、アルゴリズムの検証や改善がより柔軟になります。GANは、価格の時系列データやまれなイベントの発生といった多様な形式のデータを生成できるため、従来のデータセットでは再現が難しいシナリオでのテストが可能になります。

合成金融モデルの構築は、まずGANを用いて現実世界に近いデータを生成することから始まります。この複雑なプロセスでは、生成データの信頼性を確保するための複数の重要なステップが含まれ、金融モデリングや戦略設計の精度を高めることに寄与します。

金融データの予測に向けてGANの学習を開始するには、まずEURUSDなどの為替レートの履歴データを収集する必要があります。このデータはGANの学習における基礎的な素材となります。取得した生の金融データは、欠損値の除去や正規化といった前処理を経て整形されます。これによりデータの一貫性が保たれ、スケーリング処理によって値が-1〜1の範囲に正規化され、GANの学習効率が向上します。さらに、この時系列データからは、予測に有用な特徴量(派生データ)を抽出することが求められます。

データの取得が完了した後、GANのアーキテクチャが設計されます。ここでは、Generatorネットワークがランダムノイズを入力として受け取り、そこからデータを合成します。ランダムベクトル、すなわち潜在空間がこのネットワークへの入力となり、実際のデータに見られるパターンの再現を目指します。生成モデルは、生成されたデータが本物のデータにどれほど近いかを評価するDiscriminatorからのフィードバックに基づき、出力を反復的に調整します。この継続的な学習プロセスは、GeneratorとDiscriminatorという2つの構成要素の競合的な相互作用によって進行します。Generatorはデータシミュレーションの精度向上を目指し、Discriminatorは実データと合成データを区別する能力を強化していきます。

学習プロセスでは、GeneratorとDiscriminatorの両方のネットワークを同時に最適化するために、複数のエポックを実行します。収束を確実にするには、学習率を慎重に調整する必要があります。GeneratorはDiscriminatorを欺くことで損失を最小化することを目指し、一方でDiscriminatorは、実データと偽データを正確に区別する能力を最大化するように学習し、訓練全体を通じて2つの異なる損失関数によって導かれます。

合成シンボルは、過去のデータを強化してより優れたモデリングツールを提供することで、トレーダーにとって重要な役割を果たします。これらは現実的な市場行動をシミュレートし、大幅な下落や高いボラティリティを含むさまざまな市場状況下で取引戦略をテストするための多様なデータセットを提供します。これにより、単一の履歴トレンドへの依存を防ぎ、機械学習モデルの過学習を軽減します。さらに、合成データは仮説的なシナリオの検討を可能にし、トレーダーが予期しない市場変動を見越す手助けとなります。最終的に、トレーダーはこのシステムを活用して取引戦略を効果的に開発および洗練させることができます。


MQL5における合成データの生成

MQL5における合成データの生成は、機械学習とプラットフォームの機能を組み合わせた体系的なプロセスです。GANテクノロジーを用いて、実際の取引パターンに一致する現実的な金融データを生成します。以下に、その手順をステップバイステップで解説します。

まず、GANによって生成された合成データをMetaTrader 5の要件に合わせてエクスポートします。  GANモデルは、基本的な価格情報を含む標準的なCSVファイル形式で、MetaTrader 5が読み込める合成市場データを作成します。プラットフォームとスムーズに連携させるために、CSVの構造をMetaTraderのシステム標準に合わせて準備します。

この合成データを取引で使用するには、MetaTrader 5にカスタム銘柄としてインポートする必要があります。MetaTrader 5の[銘柄]タブを開き、新しい銘柄を作成します。銘柄名には「SYNTH_EURUSD」などの適切な名前を付けます。MQL5のCustomRatesUpdate関数を使用して、CSVから合成シンボルにデータを読み込みます。このシステムツールにより、合成時系列データが取引プラットフォームにアップロードされ、利用可能になります。最後に、気配値表示で新しい合成シンボルを確認します。作成したデータ構造と一致していることを確認してください。  

これらの手順を通じて、トレーダーは独自の合成データをMetaTrader 5プラットフォームに統合し、現実の市場環境を模したシナリオで戦略開発をおこなうことができるようになります。

以下は、CSVファイルからMetaTrader 5に合成EURUSDデータをインポートする方法を示すコードです。合成シンボルの作成、そのプロパティの設定、およびCSVからの履歴データの更新をおこないます。

#define SYNTHETIC_CSV_FILE_NAME "EURUSD_3_years_synthetic.csv"
// Function to read synthetic data from a CSV filebool ReadSyntheticDataFromCSV(const string fileName, MqlRates &rates[])
{    int fileHandle = FileOpen(fileName, FILE_CSV | FILE_READ | FILE_ANSI);
    if (fileHandle == INVALID_HANDLE)    {
        Print("Error opening file: ", GetLastError());        return false;
    }
    ArrayResize(rates, 0);
    while (!FileIsEnding(fileHandle))    {
        string line = FileReadString(fileHandle);        StringReplace(line, ",", ".");
        string fields[];        int fieldCount = StringSplit(line, ';', fields);
        if (fieldCount >= 6)
        {            MqlRates rate;
            rate.time = (datetime)StringToTime(fields[0]);            rate.open = StringToDouble(fields[1]);
            rate.high = StringToDouble(fields[2]);            rate.low = StringToDouble(fields[3]);
            rate.close = StringToDouble(fields[4]);            rate.tick_volume = (long)StringToInteger(fields[5]);
            rate.spread = 0;            rate.real_volume = 0;
            int currentSize = ArraySize(rates);
            ArrayResize(rates, currentSize + 1);            rates[currentSize] = rate;
        }    }
    FileClose(fileHandle);
    Print("Synthetic data successfully read from CSV.");    return true;
}
void OnStart(){
   string syntheticSymbol = "SYNTH_EURUSD";
   // Step 1: Create or Reset the Synthetic Symbol   if (!CustomSymbolCreate(syntheticSymbol))
   {      Print("Error creating synthetic symbol: ", GetLastError());
      return;   }
   // Step 2: Configure the Symbol Properties
   CustomSymbolSetInteger(syntheticSymbol, SYMBOL_DIGITS, 5);   CustomSymbolSetDouble(syntheticSymbol, SYMBOL_POINT, 0.00001);
   CustomSymbolSetDouble(syntheticSymbol, SYMBOL_TRADE_TICK_VALUE, 1);   CustomSymbolSetDouble(syntheticSymbol, SYMBOL_TRADE_TICK_SIZE, 0.00001);
   CustomSymbolSetInteger(syntheticSymbol, SYMBOL_SPREAD_FLOAT, true);
   // Step 3: Load Data from CSV   MqlRates rates[];
   if (!ReadSyntheticDataFromCSV(SYNTHETIC_CSV_FILE_NAME, rates))   {
      Print("Error reading synthetic data from CSV.");      return;
   }
   // Step 4: Update Rates and Add to Market Watch   if (!CustomRatesUpdate(syntheticSymbol, rates))
   {      Print("Error updating synthetic symbol rates: ", GetLastError());
      return;   }
   MarketBookAdd(syntheticSymbol); // Add to Market Watch
   Print("Synthetic symbol successfully created and added to Market Watch.");}

  • このスクリプトをMetaEditorに追加してコンパイルします。
  • MetaTrader 5のナビゲータパネルから実際のEURUSDでスクリプトを実行します。
  • インポートされたデータとともに合成シンボルが気配値表示ウィンドウに表示されることを確認します。

以下は、合成シンボル「SYNTH_EURUSD」のチャートウィンドウです。

合成シンボルが構築された後は、実際の市場データとの整合性を検証する必要があります。この分析では、2つのデータセットが基本的なパターンを維持しているかを確認するために、統計的検定を使用します。これらの検定により、シミュレーションされたデータが実際の市場データと同様の挙動を示していることが確認され、取引プラットフォームの信頼性が維持されます。以下に、適用された統計手法を示します。


シャピロ–ウィルク検定

この検定は、データが正規分布に従っているかどうかを評価するためのものです。統計的手法を用いて、合成データが実際の市場における価格変動パターンと一致しているかどうかをトレーダーが検証します。データセット同士の分布が一致していれば、現実的なデータモデリングができていると判断できます。

  • 仮説:
    • H₀(帰無仮説):データは正規分布に従う
    • H₁(対立仮説):データは正規分布に従わない

判定基準:

  • p > 0.05の場合:データは正規分布に従っている可能性が高い(H₀を採択)
  • p ≤ 0.05の場合:データは正規分布に従っていない(H₀を棄却)

記事からの例

履歴のEURUSDデータと合成のEURUSDデータを同じ時間軸に揃え、両方のデータセットにシャピロ–ウィルク検定を適用して分布の比較をおこないます。

結果:

  • 合成データ: W = 0.998、p = 0.432
  • 実データ: W = 0.997、p = 0.398

両データセットともp > 0.05であり、正規分布に従っていると判断されます。

以下は、scipy.statsライブラリを用いてシャピロ–ウィルク検定を実行するPythonコードの例です。

import pandas as pd
from scipy.stats import shapiro

# Load synthetic and real datasets
synthetic_data = pd.read_csv('EURUSD_3_years_synthetic(1).csv')
real_data = pd.read_csv('EURUSD_CSV(1).csv')

# Select the 'close' column for the test
synthetic_close = synthetic_data['close']
real_close = real_data['close']

# Perform Shapiro-Wilk test
synthetic_stat, synthetic_p = shapiro(synthetic_close)
real_stat, real_p = shapiro(real_close)

# Print results
print("Shapiro–Wilk Test Results:")
print(f"Synthetic Data W-statistic: {synthetic_stat:.4f}, P-value: {synthetic_p:.4f}")
print(f"Real Data W-statistic: {real_stat:.4f}, P-value: {real_p:.4f}")

# Interpretation
if synthetic_p > 0.05:
    print("Synthetic data follows a normal distribution.")
else:
    print("Synthetic data does not follow a normal distribution.")

if real_p > 0.05:
    print("Real data follows a normal distribution.")
else:
    print("Real data does not follow a normal distribution.")


t検定

t検定は、2つのデータセットの平均値が統計的に等しいかどうかを判断するために使用されます。金融モデルでは、合成データの価格挙動が実際の市場パターンと一致しているかを確認する必要があります。この分析により、価格が通常の市場においてどのように上下するかを検証できます。

  • 仮説:
    • H₀:平均値は等しい
    • H₁:平均値は等しくない

判定基準:

  • p > 0.05の場合:平均値に有意な差はない(H₀を採択)
  • p ≤ 0.05の場合:平均値に有意な差がある(H₀を棄却)

記事からの例

同一の時間枠に基づく合成および実際のEURUSDデータを用いて、独立2標本t検定を実施し、平均値に差があるかどうかを評価します。

結果:

  • T=0.534、p=0.594

p > 0.05であるため、2つのデータセットの平均値に有意な差は認められません。

以下は、合成データと実データの「close」列の平均値を比較するためにt検定を実行するPythonコードの例です。

import pandas as pd
from scipy.stats import ttest_ind

# Load synthetic and real datasets
synthetic_data = pd.read_csv('EURUSD_3_years_synthetic(1).csv')
real_data = pd.read_csv('EURUSD_CSV(1).csv')

# Select the 'close' column for the test
synthetic_close = synthetic_data['close']
real_close = real_data['close']

# Perform Student's t-test
t_stat, p_value = ttest_ind(synthetic_close, real_close, equal_var=False)  # Use equal_var=False if variances are unequal

# Print results
print("Student's T-Test Results:")
print(f"T-statistic: {t_stat:.4f}, P-value: {p_value:.4f}")

# Interpretation
if p_value > 0.05:
    print("The means of the synthetic and real data are not significantly different.")
else:
    print("The means of the synthetic and real data are significantly different.")


ルビーン検定

この検定は、2つのデータセット間における分散の安定性を比較するために使用されます。価格の変動レベルは取引データの分散として現れます。検証により、合成データが実際の市場データと類似した価格変動パターンを示すことが確認されれば、それが市場行動を正確に再現していることを意味します。

  • 仮説:
    • H₀:分散は等しい
    • H₁:分散は等しくない

判定基準:

  • p > 0.05の場合:分散に統計的な差はない(H₀を採択)
  • p ≤ 0.05の場合:分散に有意な差がある(H₀を棄却)

記事からの例

合成および実際のEURUSDデータの分散を比較し、それぞれの価格変動パターンに差があるかを評価します。

結果:

  • W=0.8742、p=0.3517

p > 0.05であるため、2つのデータセットの分散に有意な差は認められません。

以下は、合成データと実データの「close」列の分散を比較するためにルビーン検定を実行するPythonコードの例です。

import pandas as pd
from scipy.stats import levene

# Load synthetic and real datasets
synthetic_data = pd.read_csv('EURUSD_3_years_synthetic(1).csv')
real_data = pd.read_csv('EURUSD_CSV(1).csv')

# Select the 'close' column for the test
synthetic_close = synthetic_data['close']
real_close = real_data['close']

# Perform Levene's test
stat, p_value = levene(synthetic_close, real_close)

# Print results
print("Levene's Test Results:")
print(f"Statistic: {stat:.4f}, P-value: {p_value:.4f}")

# Interpretation
if p_value > 0.05:
    print("The variances of the synthetic and real data are not significantly different.")
else:
    print("The variances of the synthetic and real data are significantly different.")


結論

本記事では、限られた過去データ、代表性に欠けるサンプル、不十分なストレステストといった課題に対処する手段として、合成データが金融分析をいかに改善するかを解説しました。

MQL5のツールと敵対的生成ネットワーク(GAN)を組み合わせることで、トレーダーはさまざまな市場環境を再現する高品質な合成データセットを生成できます。この仕組みにより合成シンボルを作成するためのフレームワークが構築され、シャピロ–ウィルク検定やt検定といった統計的検証手法を通じて、実際の市場データとの類似性が確認されます。

合成シンボルは、堅牢な戦略検証を可能にし、最適化バイアスを軽減し、市場変動に対する戦略の耐性を高めます。これにより、トレーダーはより自信を持って戦略の洗練と改善に取り組むことができます。最終的にこのアプローチは、取引アルゴリズムと意思決定の高度化を促進し、変化の激しい市場環境にも適応可能な柔軟性の高い金融システムの実現に貢献します。

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

添付されたファイル |
プライスアクション分析ツールキットの開発(第10回):External Flow (II) VWAP プライスアクション分析ツールキットの開発(第10回):External Flow (II) VWAP
私たちの総合ガイドで、VWAPの力を完全にマスターしましょう。MQL5とPythonを活用して、VWAP分析を取引戦略に統合する方法を学びます。市場に対する洞察を最大限に活かし、より良い取引判断を下せるようになりましょう。
MQL5での取引戦略の自動化(第4回):Multi-Level Zone Recoveryシステムの構築 MQL5での取引戦略の自動化(第4回):Multi-Level Zone Recoveryシステムの構築
この記事では、RSI(相対力指数)を活用して取引シグナルを生成する、MQL5によるMulti-Level Zone Recoveryシステムの開発について解説します。本システムでは、各シグナルインスタンスを動的に配列構造に追加し、Zone Recoveryロジックの中で複数のシグナルを同時に管理することが可能になります。このアプローチにより、スケーラブルかつ堅牢なコード設計を維持しながら、複雑な取引管理シナリオに柔軟かつ効果的に対応できる方法を紹介します。
MQL5で自己最適化エキスパートアドバイザーを構築する(第5回):自己適応型取引ルール MQL5で自己最適化エキスパートアドバイザーを構築する(第5回):自己適応型取引ルール
インジケーターを安全に使用する方法を定義したベストプラクティスに従うのは、必ずしも容易ではありません。市場の動きが穏やかな状況では、インジケーターが意図した通りのシグナルを発しないことがあり、その結果、アルゴリズム取引における貴重なチャンスを逃してしまう可能性があります。本稿では、この問題に対する潜在的な解決策として、利用可能な市場データに応じて取引ルールを適応させることが可能な取引アプリケーションの構築方法を提案します。
独自のLLMをEAに統合する(第5部):LLMによる取引戦略の開発とテスト(IV) - 取引戦略のテスト 独自のLLMをEAに統合する(第5部):LLMによる取引戦略の開発とテスト(IV) - 取引戦略のテスト
今日の人工知能の急速な発展に伴い、言語モデル(LLM)は人工知能の重要な部分となっています。私たちは、強力なLLMをアルゴリズム取引に統合する方法を考える必要があります。ほとんどの人にとって、これらの強力なモデルをニーズに応じてファインチューニングし、ローカルに展開して、アルゴリズム取引に適用することは困難です。本連載では、この目標を達成するために段階的なアプローチをとっていきます。