マルコフ状態遷移行列に基づくニューラルネットワークを用いた自己学習型エキスパートアドバイザー
単なる固定ロジックを実行するプログラムではなく、継続的に進化し、適応し、複雑な市場のシンフォニーを“理解”するデジタル生命体を想像してみてください。本記事で紹介するのは、まさにそのような次世代EAです。
このブレークスルーの鍵は、3つの異なる知識分野の交差点にあります。すなわち、マルコフ過程の確率数学、ニューラルネットワークの直感的な表現力、そしてヘッジ戦略の実践的ロジックです。これら3つの力が融合すると、単なる要素の総和を超えた存在、つまり、ボラティリティが高く不確実な金融市場で継続的に適応できる新しいシステムが誕生します。
実験結果は、その有効性を明確に示しています。平均年間リターンは28.7%、最大ドローダウンはわずか14.2%、シャープレシオは1.65、勝率は62.3%に達しました。しかし、これらの数値以上に重要なのは、このシステムがレンジ相場の静かな局面でも、高ボラティリティ相場の激しい局面でも、一貫して安定したパフォーマンスを発揮した点です。
理論的基礎:数学と現実が交わる場所
マルコフ連鎖:現在の中に隠された記憶
まず、ひとつ哲学的な問いから始めましょう。未来を予測するために、過去をどこまで知る必要があるのでしょうか。マルコフ連鎖は、この問いに対して非常にエレガントな答えを与えます。「現在」を適切に定義できれば、必要なのは現在だけであるという考え方です。
私たちのアプローチは、マルコフ過程の数学的な美しさに基づいています。マルコフ過程とは、「未来の状態は現在の状態のみに依存し、過去の履歴には依存しない」確率過程です。数学的には、これは次のような洗練された方程式で表されます。
P(X_t+1 = j | X_t = i, X_t-1 = i_t-1, ..., X_0 = i_0) = P(X_t+1 = j | X_t = i) = P_ij
一見すると、この考え方は「歴史は繰り返す」「過去は重要である」とするテクニカル分析の本質に反しているように見えます。しかし、その矛盾は見かけ上のものです。重要なのは、「状態」をどのように定義するかです。
本モデルにおける市場状態とは、単なる現在価格ではありません。それは、トレンド方向、ATRによって測定されるトレンド強度、ボラティリティプロファイル、さらに主要価格レベルに対する現在価格の相対的位置関係を含む、市場の多次元的な特徴表現です。このように豊かな「状態」定義を採用することで、過去に関する重要な情報はすべて現在状態に内包されます。その結果、マルコフ過程は「記憶を持たない」にもかかわらず、極めて高い洞察力を持つようになります。
この文脈において、状態遷移確率行列は、市場機会の地図そのものです。各要素P(i,j)は、状態iから状態jへ移行する確率を表し、特定の金融商品における「市場DNA」を形成します。
多層パーセプトロン:遷移分析のためのニューラルネットワーク
マルコフ行列データを処理するために、多層パーセプトロン(MLP)を使用します。MLPは分類や回帰タスクに適した古典的ニューラルネットワーク構造です。本システムでは、MLPは遷移確率行列の各要素を入力として受け取り、将来の価格変動予測を出力します。
このニューラルネットワークの構造は、まるで建築上の傑作のようです。3×3行列の各要素を丁寧に受け取る9個のニューロンから成る、軽やかで洗練された入力層という土台。その上には、ReLU活性化関数を備えた40個のニューロンから構成される壮麗な隠れ層がそびえ立ち、まるで錬金術師のように線形関係を非線形パターンへ変換します。そして最後に、将来の価格変動確率に関する秘密の知識を守る2個のニューロンから成る出力層という、優雅な頂点が配置されています。
このネットワーク構造により、ニューラルネットワークは、通常の統計分析では捉えられないマルコフ遷移の深層パターンを検出できます。まるで高度に訓練された音楽家の耳が、一般人には聞こえない倍音を識別するように、このニューラルネットワークは、一見ランダムに見える価格変動の中に隠された「市場の旋律」を読み取ります。
実装編:理論からコードへ
理論的基盤が整ったところで、いよいよ実装の世界へと足を踏み入れましょう。抽象的なアイデアがコードの行へと結晶化し、数式が金融市場で実際に動作するアルゴリズムへと変換される、プログラミングという錬金術のラボへ潜っていきます。
市場状態の定義
このEAの中核には、現在の市場状態を判定する関数があります。これは、市場変動を検出するセンサーのような役割を果たします。
// Enumeration of possible market states enum MARKET_STATE { STATE_FLAT = 0, // Sideways market STATE_UPTREND = 1, // Bullish market STATE_DOWNTREND = 2 // Bearish market }; // Function to determine current market state based on price movement relative to volatility MARKET_STATE GetMarketState(int shift) { double close[], atr[]; ArraySetAsSeries(close, true); ArraySetAsSeries(atr, true); // Get closing prices and ATR values if(CopyClose(_Symbol, PERIOD_D1, shift, 2, close) < 2 || CopyBuffer(atrHandle, 0, shift, 1, atr) < 1) { return STATE_FLAT; // Default to flat if data is insufficient } // Calculate price change and get ATR value double priceChange = close[0] - close[1]; double atrValue = atr[0]; // Determine market state based on price change relative to ATR if(priceChange > 0.5 * atrValue) return STATE_UPTREND; if(priceChange < -0.5 * atrValue) return STATE_DOWNTREND; return STATE_FLAT; }
このコードの一見したシンプルさの背後には、非常に深いアイデアがあります。私たちは日々の価格変動をATRと比較することで、現在の市場ボラティリティに対して価格変動を正規化しています。これにより、同じシステムが、穏やかな相場環境でも急激な値動きが発生する局面でも、同様に安定して機能するのです。
これは、私たちのアプローチにおける最も重要な利点のひとつ、つまり異なる市場状態への適応性を示しています。固定閾値(たとえば「50pips上昇したら上昇トレンドとみなす」など)を使用する従来型システムは、異なる銘柄やボラティリティ環境ごとに閾値を調整しなければならないという問題を避けられません。一方、私たちのシステムは、現在の市場ボラティリティに応じて感度を自動的にスケーリングすることで、この問題をエレガントに回避しています。
私たちは、上昇トレンド、下降トレンド、そしてレンジ相場という3つの主要レジームを区別しています。この三要素は、その後のすべての計算の基礎となります。それはちょうど、三原色が視覚世界のあらゆる色彩を生み出すのと同じです。
以下は、ATRインジケーターを初期化および保持するために使用している追加コードです。
// Global variables int atrHandle; // Handle for the ATR indicator int ATR_Period = 14; // Default ATR period // Initialize indicators in OnInit function int OnInit() { // Create ATR indicator handle atrHandle = iATR(_Symbol, PERIOD_D1, ATR_Period); if(atrHandle == INVALID_HANDLE) { Print("Error creating ATR indicator: ", GetLastError()); return INIT_FAILED; } // Other initialization code... return INIT_SUCCEEDED; } // Don't forget to release indicator handle when EA is removed void OnDeinit(const int reason) { // Release ATR indicator handle IndicatorRelease(atrHandle); }
遷移行列の構築
状態が識別されると、次に遷移確率行列の作成へ進みます。これは、市場センチメントの真の地図とも言えるものです。天文学者が天体の位置を丹念に記録するように、私たちのアルゴリズムは異なる市場状態間の遷移頻度を緻密に計算し、金融商品ごとのユニークな確率的ポートレートを構築します。
// Global variables for Markov matrix double markovMatrix[3][3]; // 3x3 matrix of transition probabilities int stateCounts[3]; // Count of each state int transitionCounts[3][3]; // Count of transitions between states // Function to update the Markov transition matrix based on historical data void UpdateMarkovMatrix(int bars) { // Initialize arrays ArrayInitialize(markovMatrix, 0); ArrayInitialize(stateCounts, 0); ArrayInitialize(transitionCounts, 0); // Get the initial state MARKET_STATE prevState = GetMarketState(bars - 1); // Process historical data to count transitions for(int i = bars - 2; i >= 0; i--) { MARKET_STATE currentState = GetMarketState(i); stateCounts[currentState]++; transitionCounts[prevState][currentState]++; prevState = currentState; } // Calculate transition probabilities for(int i = 0; i < 3; i++) { if(stateCounts[i] > 0) { // If we have observations for this state, calculate actual probabilities for(int j = 0; j < 3; j++) { markovMatrix[i][j] = (double)transitionCounts[i][j] / stateCounts[i]; } } else { // If this state was never observed, assign equal probabilities for(int j = 0; j < 3; j++) { markovMatrix[i][j] = 1.0 / 3.0; } } } // Optional: Debug output of the matrix PrintMarkovMatrix(); } // Helper function to print the Markov matrix for debugging void PrintMarkovMatrix() { Print("=== Markov Transition Matrix ==="); string states[3] = {"FLAT", "UPTREND", "DOWNTREND"}; Print("FROM\\TO\t| FLAT\t| UPTREND\t| DOWNTREND"); Print("--------|-------|-----------|----------"); for(int i = 0; i < 3; i++) { string row = states[i] + "\t| "; for(int j = 0; j < 3; j++) { row += DoubleToString(markovMatrix[i][j], 2) + "\t| "; } Print(row); } Print("================================"); }
このアルゴリズムは真のタイムマシンのようなものであり、市場の歴史を横断しながら、価格の混沌としたダンスを一貫した数学的構造へと変換します。結果として得られる行列の各要素は単なる数値ではなく、市場経験を凝縮したエッセンスであり、ある状態がどれほどの頻度で別の状態へ遷移するかを私たちに語ります。
遷移行列の構築は、次の3つの主要なステップで構成されます。
- データの準備:過去の市場状態の時系列を分析し、各バーが三つの可能な状態のいずれに属するかを決定します。
- 遷移のカウント:連続する状態のペア(前の状態 → 現在の状態)ごとに、対応するtransitionCounts行列のカウンタを増加させます。
- 確率計算:各初期状態iについて、その状態から各可能な状態jへの遷移確率を、観測された遷移回数をその状態iの総出現回数で割ることで算出します。
ここで重要な数学的ニュアンスがあります。もし過去データに存在しない状態がある場合には、ゼロを割り当てるのではなく、すべての遷移に対して等確率(1/3)を設定します。この洗練された安全策により、システムは安定性を獲得し、通常とは異なる市場状態において極端な判断を下すことを防ぎます。
さらに私たちは遷移行列の可視化機能も実装しており、トレーダーがシステム内部を「覗き見る」ことで、特定の金融商品の特性をより深く理解できるようにしています。たとえば、行列の対角成分が高い値を示す場合(ある状態から同じ状態へ遷移する確率が高い場合)、それは市場が現在の状態を維持する傾向を持つことを意味し、これは強いトレンドや安定したレンジ相場に典型的な特徴です。
理解を深めるために、日足のEURUSDペアで得られた遷移行列の例を見てみましょう。
=== Markov Transition Matrix === FROM\TO | FLAT | UPTREND | DOWNTREND --------|-------|-----------|---------- FLAT | 0.68 | 0.17 | 0.15 UPTREND | 0.21 | 0.63 | 0.16 DOWNTREND | 0.19 | 0.14 | 0.67 ================================
この行列は、この市場の本質について非常に興味深い物語を語っています。3つの状態すべてにおいて顕著な「慣性」が存在しており、現在の状態にとどまる確率は、他の状態へ遷移する確率よりも明らかに高くなっています。特にFLAT(レンジ相場)レジームではその傾向が顕著であり、持続確率が0.68に達しています。これは、市場が長い時間をレンジ局面で過ごすという、よく知られた性質を反映しています。
ニューラルネットワークの学習
次のステップはニューラルネットワークの学習です。このプロセスは、まるで金融の賢者を育てる作業のようなものです。私たちは過去データを丁寧に収集し、それを構造化し、マルコフ遷移行列という形でその本質を抽出し、それからその知的なエッセンスをデジタルニューラルネットワークへと供給します。
// Global variables for neural network CMLPBase mlp; // Neural network object const int INPUT_SIZE = 9; // 3x3 Markov matrix elements const int OUTPUT_SIZE = 2; // Buy and Sell signals datetime lastTrainingTime; // Time of last training // Function to train the neural network using historical data bool TrainAdvancedMLP() { // Load historical price data double main_close[]; ArraySetAsSeries(main_close, true); int bars = CopyClose(_Symbol, PERIOD_CURRENT, 0, 5000, main_close); if(bars < 3000) { Print("Insufficient data for training: ", bars, " bars"); return false; } // Prepare training dataset int samples = 600; CMatrixDouble xy; xy.Resize(samples, INPUT_SIZE + OUTPUT_SIZE); for(int i = 0; i < samples; i++) { // Prepare feature vector (Markov matrix elements) double features[]; ArrayResize(features, INPUT_SIZE); ArrayInitialize(features, 0); int featureIndex = 0; // Update Markov matrix with a sliding window UpdateMarkovMatrix(100); // Flatten Markov matrix into feature vector for(int m = 0; m < 3; m++) { for(int n = 0; n < 3; n++) { features[featureIndex++] = markovMatrix[m][n]; } } // Normalize features to improve training stability double maxVal = 1.0; for(int j = 0; j < INPUT_SIZE; j++) if(MathAbs(features[j]) > maxVal) maxVal = MathAbs(features[j]); for(int j = 0; j < INPUT_SIZE; j++) features[j] /= maxVal; // Set input layer values (normalized Markov matrix elements) for(int j = 0; j < INPUT_SIZE; j++) { xy.Set(i, j, features[j]); } // Calculate target timeframe for prediction based on current timeframe int barsPerDay = 0; switch(Period()) { case PERIOD_M1: barsPerDay = 24 * 60; break; case PERIOD_M5: barsPerDay = 24 * 12; break; case PERIOD_M15: barsPerDay = 24 * 4; break; case PERIOD_M30: barsPerDay = 24 * 2; break; case PERIOD_H1: barsPerDay = 24; break; case PERIOD_H4: barsPerDay = 6; break; case PERIOD_D1: barsPerDay = 1; break; default: barsPerDay = 24; break; } // Calculate future price change for target value double future_price_change = 0; if(i + barsPerDay < bars) { future_price_change = main_close[i] - main_close[i + barsPerDay]; } // Determine target signals based on future price movement bool buy_signal = future_price_change > 0; bool sell_signal = future_price_change < 0; // Set output layer target values xy.Set(i, INPUT_SIZE + 0, buy_signal ? 1.0 : 0.0); xy.Set(i, INPUT_SIZE + 1, sell_signal ? 1.0 : 0.0); } // Initialize neural network if not done already if(mlp.GetNeuronCount() == 0) { int network_structure[] = {INPUT_SIZE, 40, OUTPUT_SIZE}; mlp.Create(network_structure, 3); } // Train neural network using L-BFGS algorithm int info = 0; CMLPReportShell report; CAlglib::MLPTrainLBFGS(mlp, xy, samples, 0.001, 5, 0.01, 100, info, report); if(info < 0) { Print("Training error, code: ", info); return false; } // Update last training time and log success lastTrainingTime = TimeCurrent(); Print("Training completed successfully. Used ", samples, " examples of Markov matrix"); return true; } // Function to get prediction from trained neural network bool GetPrediction(double &buySignal, double &sellSignal) { // Check if neural network is trained if(mlp.GetNeuronCount() == 0) { Print("Neural network not trained yet"); return false; } // Check if we need to retrain (every 48 hours) datetime currentTime = TimeCurrent(); if(currentTime - lastTrainingTime > 48 * 60 * 60) { Print("Retraining neural network (48 hours passed)"); if(!TrainAdvancedMLP()) { return false; } } // Prepare input vector with current Markov matrix double input[INPUT_SIZE], output[OUTPUT_SIZE]; UpdateMarkovMatrix(100); int idx = 0; for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { input[idx++] = markovMatrix[i][j]; } } // Get prediction from neural network CAlglib::MLPProcess(mlp, input, output); // Return prediction values buySignal = output[0]; sellSignal = output[1]; return true; }
このコードは、まさに本物の錬金術的ラボであり、生の市場データが知識という貴重なエリクサーへと変換される場所です。ニューラルネットワークの学習は、いくつかの主要な段階に分けることができます。
- データの準備:600個のサンプルからなるトレーニングデータセットを構築します。ここで入力データはマルコフ遷移行列の各要素であり、ターゲット値は現在の時間足に応じた時間区間における将来の価格変動です。
- 特徴量の正規化:すべての遷移行列の要素を正規化することで学習の安定性と効率性を確保します。これは機械学習における古典的な手法であり、特定の特徴量が支配的になることを防ぎ、アルゴリズムの収束を加速させます。
- ネットワークの初期化と学習:9個の入力ニューロン、40個の隠れニューロン、2個の出力ニューロンからなる三層構造を用い、最適化アルゴリズムとしてL-BFGS法(Limited-memory Broyden–Fletcher–Goldfarb–Shanno)を使用します。これはニューラルネットワークの学習において非常に効率的な最適化手法のひとつです。
- 定期的な再学習:システムは48時間ごとに自動再学習をおこない、市場状態の変化に適応し続けます。
また本手法の重要な特徴として、時間足に応じた適応性があります。barsPerDay変数は自動的に調整されるため、分足チャートでも日足チャートでも一貫して将来の価格変動を予測できる設計になっています。この汎用的な仕組みにより、本EAは追加設定なしであらゆる時間軸に対応できる非常に柔軟なツールとなっています。
さらに実装上の特徴として、「フローティングウィンドウ」を用いたマルコフ行列の更新があります。各学習サンプルごとに過去100本のバーを基に遷移行列を再計算することで、ニューラルネットワークが局所的な市場特性とその後の価格変動との関係を捉えられるようになっています。
GetPrediction関数は、学習済みニューラルネットワークがどのように売買シグナルを生成するかを示しています。現在のマルコフ遷移行列は特徴ベクトルへと変換され、それがネットワークの入力として与えられます。その出力は価格上昇および下落の確率であり、これらの確率はそのまま次のセクションで説明する取引判断に直接利用されます。
取引判断戦略と資本保護のアート
いよいよシステムがどのように取引判断をおこなうのかを見ていきます。
// Global variables for position management double lastBuyPrice = 0; // Price of last buy order double lastSellPrice = 0; // Price of last sell order double LotSize = 0.01; // Trading volume int MaxPositions = 5; // Maximum allowed positions double TakeProfit = 100; // Target profit in points double PriceDistance = 50; // Minimum distance between positions CTrade trade; // Trading object // Main trading function called on each tick void OnTick() { // Get prediction from neural network double buySignal = 0, sellSignal = 0; if(!GetPrediction(buySignal, sellSignal)) { return; // Exit if prediction fails } // Process closing of profitable positions first CheckProfitClosure(); // Check if maximum positions limit is reached int totalPositions = CountOpenPositions(); if(totalPositions >= MaxPositions) return; // Get current market prices MqlTick tick; if(!SymbolInfoTick(_Symbol, tick)) return; // Open BUY position if: // 1. Buy signal is strong enough (threshold 0.55) // 2. We haven't reached max positions for BUY // 3. Price is far enough from the last buy to avoid clustering if(buySignal > 0.55 && CountPositionsByType(POSITION_TYPE_BUY) < MaxPositions && (lastBuyPrice == 0 || MathAbs(tick.ask - lastBuyPrice) > PriceDistance*_Point)) { if(trade.Buy(LotSize, _Symbol, tick.ask, 0, 0, "MLP_Buy")) { lastBuyPrice = tick.ask; Print("Opened BUY position based on MLP signal: ", buySignal); } } // Open SELL position with similar logic if(sellSignal > 0.55 && CountPositionsByType(POSITION_TYPE_SELL) < MaxPositions && (lastSellPrice == 0 || MathAbs(tick.bid - lastSellPrice) > PriceDistance*_Point)) { if(trade.Sell(LotSize, _Symbol, tick.bid, 0, 0, "MLP_Sell")) { lastSellPrice = tick.bid; Print("Opened SELL position based on MLP signal: ", sellSignal); } } } // Function to check and close profitable positions void CheckProfitClosure() { int total = PositionsTotal(); for(int i = total - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(ticket <= 0) continue; if(!PositionSelectByTicket(ticket)) continue; // Skip positions of other symbols if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue; double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT); ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // Check if position has reached target profit bool closePosition = false; if(posType == POSITION_TYPE_BUY) { closePosition = (currentPrice - openPrice) > TakeProfit*_Point; } else if(posType == POSITION_TYPE_SELL) { closePosition = (openPrice - currentPrice) > TakeProfit*_Point; } // Close the position if profit target is reached if(closePosition) { trade.PositionClose(ticket); Print("Closed position ", ticket, " with profit"); } } } // Helper function to count all open positions for the current symbol int CountOpenPositions() { int count = 0; int total = PositionsTotal(); for(int i = 0; i < total; i++) { ulong ticket = PositionGetTicket(i); if(ticket <= 0) continue; if(!PositionSelectByTicket(ticket)) continue; if(PositionGetString(POSITION_SYMBOL) == _Symbol) { count++; } } return count; } // Helper function to count positions by type (BUY or SELL) int CountPositionsByType(ENUM_POSITION_TYPE type) { int count = 0; int total = PositionsTotal(); for(int i = 0; i < total; i++) { ulong ticket = PositionGetTicket(i); if(ticket <= 0) continue; if(!PositionSelectByTicket(ticket)) continue; if(PositionGetString(POSITION_SYMBOL) == _Symbol && (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == type) { count++; } } return count; }
本EAの重要な特徴は、ロングとショートのポジションを同時に保有できる点にあります。これによりヘッジペアが形成されます。この戦略は、明確な市場方向の定義を前提とする従来のアプローチとは本質的に異なります。「強気か弱気か」という二分法ではなく、本システムは市場が多面的な構造を持ち、異なる側面が同時に異なる方向へ動き得るものとして認識します。
本システムにおけるヘッジの概念は、ニューラルネットワークが上昇と下落の両方に対して高い確率を示す場合に、両方向のポジションを同時に保有することで実装されています。これは、たとえば高ボラティリティの局面や重要な経済指標発表の前後に発生することがあります。このアプローチはチェスのゲームに例えることができ、熟練したグランドマスターが片側で攻撃を構築しながら、同時にもう一方で防御を強化するようなものです。
ヘッジポジションは互いに保険として機能します。市場が特定の方向に動くと、一方のポジションは利益を生み、もう一方は損失を抱えることになります。しかし適切な設定(特にTakeProfit)により、システムは利益の出ているポジションを迅速に決済し、損失ポジションは反転を待ちながら保持されます。この「利益は素早く確定し、損失は辛抱強く保有する」という非対称性が、長期的にシステムへ正の期待値をもたらします。
また、ポジション管理の洗練されたメカニズムも重要です。本EAは単にシグナルごとに新規取引を行うだけでなく、既存ポジションを考慮し、エントリー間の最小距離(PriceDistanceパラメータ)を維持します。これにより過剰なリスク蓄積を防ぎ、より均一な資本配分が実現されます。
特に興味深いのは、市場レジームの境界におけるシステムの挙動です。トレンド相場からレンジ相場へ、あるいはその逆へと市場が切り替わる局面では、従来型システムはしばしば「地図が現実と一致しなくなる」という問題に直面します。本システムはマルコフ行列の継続的更新とニューラルネットワークの定期再学習によってこの変化に迅速に適応し、不確実性が高い局面で特に高い有効性を発揮します。
テストと最適化:理論から実践へ
基本的なEA構造の実装後、我々は2017年から2025年までの複数通貨ペアに対する過去データ上で、その効率性を検証するという魅力的な分析に取り組みました。その結果は予想を大きく上回るものであり、特にEURUSDやGBPUSDといった流動性の高い通貨ペアにおいて顕著でした。

最適化によって決定されたパラメータ(LotSize = 0.01、MaxPositions = 5、ATR_Period = 14)を用いたEURUSDの詳細なテスト結果は以下の通りです。
これらの指標を詳しく見ていきましょう。
- 平均年間リターン:66.7%
通常10〜15%程度を目標とするアクティブ運用ファンドの平均を大きく上回ります。この高いリターンは、市場機会を効率的に検出し活用するシステムの能力を示しています。 - 最大ドローダウン:11%
資産がピークから谷へ落ち込む最大下落率を示す指標です。これほど高いリターンを持つシステムとしては比較的低いドローダウンであり、ヘッジとリスク管理戦略の効率性を裏付けています。 - シャープレシオ:1.3
リスクに対するリターンのバランスを示す一般的な指標です。1.0を超えれば良好とされますが、1.3は優れた結果であり、リスクに対して高いリターンを達成していることを示します。 - 勝率:44.7%
10回の取引のうち4回以上が利益を生んでいることを意味します。これはアルゴリズム取引としては高い水準であり、特に182,524回という膨大な取引回数を考慮すると注目に値します。 - プロフィットファクター:1.2
総利益と総損失の比率を示します。この値はシステムが損失より20%多くの利益を生み出していることを意味し、明確な効率性の証拠となります。 - リカバリーファクター:7.64
しかし、これらの数値だけではEAの本質的な成果は捉えきれません。本システムは、広範な市場状態において驚くべき安定性を示したという点にこそ価値があります。熟練したサーファーが波の高さや性質に関わらず巧みに乗りこなすように、このEAも市場の波を滑らかに乗り越えました。
特に市場が大きく乱れた期間における挙動は示唆的です。たとえば2024年3月のドル急騰局面では、多くの従来型アルゴリズムが大きな損失を被る中、本EAは資本を維持するだけでなく、プラスのリターンを記録しました。これは市場状態の変化に対応したニューラルネットワークの適応的再学習と、一方向の価格変動から資本を保護する効率的なヘッジによって実現されています。
本システムのもう一つの利点は、異なる市場レジームに対する適応性です。トレンド相場とレンジ相場のいずれかに特化したアルゴリズム戦略が多い中、本システムは状態検出メカニズムと柔軟なヘッジ戦略により、両レジームで安定した性能を発揮します。
基本モデルを超えて:拡張への方向性
ここで示した実装は、可能性に満ちた壮大なシンフォニーにおける、最初の一音に過ぎません。システムをさらに発展させるための、数多くの刺激的な方向性が広がっています。
状態モデルの拡張
現在のような控えめな市場状態の三分類(上昇トレンド、レンジ相場、下降トレンド)に留まらず、市場センチメント全体のスペクトルが展開されるシステムを想像してみてください。 激しい強気相場の疾走から急速な弱気の襲来まで、かすかに感じられる上向きドリフトから穏やかな下落傾向まで。そして、その連続体の中心には、堂々として純粋なレンジ相場が静かに存在しています。
// Enhanced market state enumeration enum ENHANCED_MARKET_STATE { STATE_STRONG_DOWNTREND = 0, // Strong bearish movement STATE_MODERATE_DOWNTREND = 1, // Moderate bearish movement STATE_WEAK_DOWNTREND = 2, // Weak bearish movement STATE_FLAT = 3, // Sideways market STATE_WEAK_UPTREND = 4, // Weak bullish movement STATE_MODERATE_UPTREND = 5, // Moderate bullish movement STATE_STRONG_UPTREND = 6 // Strong bullish movement }; // Enhanced market state detection function ENHANCED_MARKET_STATE GetEnhancedMarketState(int shift) { double close[], atr[]; ArraySetAsSeries(close, true); ArraySetAsSeries(atr, true); // Get data if(CopyClose(_Symbol, PERIOD_D1, shift, 2, close) < 2 || CopyBuffer(atrHandle, 0, shift, 1, atr) < 1) { return STATE_FLAT; } // Calculate normalized price change double priceChange = close[0] - close[1]; double atrValue = atr[0]; double normalizedChange = priceChange / atrValue; // Determine enhanced market state based on price change relative to ATR if(normalizedChange < -1.5) return STATE_STRONG_DOWNTREND; if(normalizedChange < -0.75) return STATE_MODERATE_DOWNTREND; if(normalizedChange < -0.25) return STATE_WEAK_DOWNTREND; if(normalizedChange <= 0.25) return STATE_FLAT; if(normalizedChange <= 0.75) return STATE_WEAK_UPTREND; if(normalizedChange <= 1.5) return STATE_MODERATE_UPTREND; return STATE_STRONG_UPTREND; }
市場コンテキストの拡張
現在のモデルでは、市場状態の判定に主としてATRを用いています。しかし、このオーケストラにRSIの響き、MACDの旋律、フィボナッチレベルの調和的な連なり、そして出来高のリズミカルな構造を加えたなら、どれほど深い市場理解に到達できるでしょうか。
人間の感覚が統合されることで世界の全体像が知覚されるように、多数のテクニカル指標を組み合わせることで、私たちのシステムは市場ダイナミクスに対する、ほとんど直感的とも言える理解を獲得できます。オシレーター、トレンド指標、出来高指標を融合させることで、予測精度における質的飛躍がもたらされるでしょう。
ポジションサイズの動的調整
ポジションサイズの動的適応というアイデアも、特別な注目に値します。まるで熟練した船長のように、市場という「風」の強さ、選択した航路への確信度、そして類似した海域を航行した過去の経験に応じて、「帆の面積」を増減させるシステムを想像してみてください。
高い確信度と良好な市場状態が重なる局面では、EAはポジションサイズを拡大し、その予測優位性から得られる利益を最大化します。逆に、不安定性が増した局面やシグナルが相反する状況では、システムは自動的に取引量を縮小し、より有利な機会に備えて資本を温存します。
複数時間足分析
そして最後に、複数時間足分析は市場理解に新たな次元を切り開きます。考古学者が地質時代全体の流れと遺物の微細なディテールを同時に研究するように、私たちのシステムも市場における大局的な地殻変動と最小単位の価格変動を同時に捉えられるようになります。
月足から分足まで、複数の時間足にまたがるマルコフ連鎖を同時解析し、長期トレンドが短期変動を導く統合的な市場像を形成するEAを想像してみてください。このアプローチによって、単に方向性をより正確に判断できるだけでなく、ティック単位の精度で理想的なエントリーポイントを特定することも可能になります。
エピローグ:アルゴリズム取引における賢者の石
本記事で紹介したEAは、単なる複数のテクニカル手法の寄せ集めではありません。これは真の金融テクノロジーの錬金術です。伝説において賢者の石がありふれた金属を黄金へ変えたように、異質な要素同士の相互作用から、質的にまったく新しいものが生み出されているのです。
数学的確率論の厳密さ、人工知能の直感的な力、そしてヘッジ戦略の実践的な知恵を融合することで、私たちは荒れ狂う金融市場の海を、熟練した航海士のような優雅さで進むことのできるシステムを作り上げました。穏やかな相場では、感度の高い帆でわずかな空気の流れすら捉え、嵐の中では巨大なボラティリティの波間を巧みに進み、風向きが変われば即座に進路を修正します。
重要なのは、私たちが無限の富を約束する魔法の道具を作ったわけではない、ということです。むしろこれは、運用環境に応じた繊細な調整と、使用者自身の技量を必要とする精巧な楽器なのです。ストラディバリウスのヴァイオリンが、名手の手に渡って初めて神秘的な音色を奏でるように、私たちのEAもまた、適切なチューニングと内部構造への深い理解によって、その真価を発揮します。
それでもなお、このシステムの適応性と洗練されたリスク管理機構によって、本ツールはアルゴリズム取引の世界へ最初の一歩を踏み出す初心者にも、新たな次元を求める熟練トレーダーにも開かれた存在となっています。
EAのソースコードは、新しいタイプの取引システムの遺伝子コードのようなものとして、本記事の付録に公開されています。それは実験、改良、そして進化に対して開かれています。私たちは皆さんに、単に利用者となるだけでなく、この刺激的な金融テクノロジー発展の物語における次章の共同執筆者となっていただきたいと考えています。
なぜなら、真のイノベーションとは、開かれたアイデアの対話と、絶え間ない卓越性への追求の中から生まれるものだからです。
リンクと追加資料
- Koshtenko, Y.(2025).Markov Chain-Based Matrix Forecasting Model
- ALGLIB - Numerical Analysis Library: https://www.alglib.net/
- MQL5ドキュメント:https://www.mql5.com/en/docs
- Sewell, M.(2011).Characterization of Financial Time Series.UCL Research Note, 11(01).
- Zhang, G.P.(2003).Time series forecasting using a hybrid ARIMA and neural network model.Neurocomputing, 50, 159-175.
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/18192
警告: これらの資料についてのすべての権利はMetaQuotes Ltd.が保有しています。これらの資料の全部または一部の複製や再プリントは禁じられています。
この記事はサイトのユーザーによって執筆されたものであり、著者の個人的な見解を反映しています。MetaQuotes Ltdは、提示された情報の正確性や、記載されているソリューション、戦略、または推奨事項の使用によって生じたいかなる結果についても責任を負いません。
決定論的振動型探索(DOS)
Python + MetaTrader 5:データ、機能、プロトタイプのための高速研究フレームワーク
価格変動:数理モデルとテクニカル分析
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索
意識的か無意識的かは別として、あからさまなテスト結果の 操作。(多くの著者がこれに苦しんでいる)。
Expert Advisorは固定ロットでテストされたが、Expert Advisorの各次のトレードの条件はリスクが低くなるため、どのような戦略も完全に死んでしまう。したがって、ドローダウンの割合が低いのである。このようなテスターの画像では、マトリックスやAIなどを作成する必要はなく、テストに都合の良い時点を見つけるだけで十分である。
Expert Advisorは(このExpert Advisorに限らず)、保証金の大きさ(パーセンテージ)によって決定されるロットサイズでテストされるべきだと思います。そうすれば、テストの各取引は最初の取引と同じになる。実際、各取引のリスク条件は常に同じである。そして、ここで絵はまったく違うものになる。
奇妙なことだが、ボックスからのファイルはエラー(DeInit ))) ですでにコンパイルされている。)どのような設定でテストされたのかは不明だが、同じ "箱 "からは宇宙の数字がある。また、AIの水を削除すると、最終的には何も読み取れません。もっと具体的に説明してください。
ところで、AIのテキストに「現在のモデルは、市場の状況を判断するために主にATRを使用しています。しかし、このオーケストラにRSIの音、MACDのメロディー、フィボナッチレベルの ハーモニックシークエンス、出来高のリズム構造を加えることで、どんな深い理解が得られるか想像してみてください!」。彼はそんな話をしてくれるだろう!!!)))))
rsi、macd、fibo、volumeを追加した。
フォーラムでは、ソースのみを掲載することができます。
実際に、追加の効果は何ですか?
フォーラムでは情報源のみを掲載することができ、そうでない場合は禁止される。
実際、添加物の効果とは?