English
preview
既存のMQL5取引戦略へのAIモデルの統合

既存のMQL5取引戦略へのAIモデルの統合

MetaTrader 5トレーディング |
42 1
Hlomohang John Borotho
Hlomohang John Borotho

はじめに

本記事では、既存のMQL5取引戦略にAIモデルを統合します。前回の記事で紹介したオーダーブロックとフィボナッチを活用しながら進めていきます。多くの既存のMQL5取引戦略は、固定されたインジケーター、厳格な閾値、またはあらかじめ定義されたパターンに依存しており、異なる市場サイクルでは効果的でない場合があります。これらの戦略は、過去のデータから学習したり、複雑なパターンを認識したり、変化する市場環境に応じて柔軟に判断を調整する能力を欠いています。

AIモデルをMQL5の取引戦略に組み込むことで、こうした課題を克服し、機械学習に基づく適応性と意思決定能力を取り入れることが可能になります。たとえば、長短期記憶(LSTM)や予測分析などの技術を用いることで、AIは膨大な過去およびリアルタイムのデータを分析し、よりスマートな取引アクションを生み出すことができます。従来のような硬直的な戦略とは異なり、AIを活用したシステムは、市場の変化に応じて動的に学習・進化し、戦略を洗練させていきます。これにより、エントリーやエグジットのタイミングが向上し、リスク管理の精度が高まり、長期的な収益性の向上が期待できます。


導入手順

最初のステップは、既存のMQL5コードをPythonに変換することです。AIを取引戦略に統合するためには、元のMQL5ロジックをPythonベースで再現することが不可欠です。この変換により、戦略の基本機能を損なうことなく、AIによる高度な処理をシームレスに組み込むことが可能になります。Python版のコードでは、MQL5スクリプトの動作を正確に再現する必要があります。具体的には、取引実行ロジック、インジケーターの計算、注文管理、リスク管理ルールなどが含まれます。これにより、AIモデルはMetaTrader 5上で稼働しているシステムと同一の挙動を持つ環境で動作することになり、統合前に正確なテストと最適化が可能になります。このステップが完了すれば、次は機械学習モデルの組み込み、市場データを用いたAIのトレーニング、そして最終的には意思決定とパフォーマンスを強化するインテリジェントかつ適応的な取引システムの構築へと進めます。

MQL5コード

#include <Trade/Trade.mqh>
#include <Arrays\ArrayObj.mqh>
CTrade trade;

#define BullOB clrLime
#define BearOB clrRed

//+------------------------------------------------------------------+
//|                           Global vars                            |
//+------------------------------------------------------------------+
double Lots = 0.01;
int takeProfit = 170;
int length = 100;
input double stopLoss = 350;
input double Mgtn = 0.85;

bool isBullishOB = false; 
bool isBearishOB = false;

input int Time1Hstrt = 3;
input int Time1Hend = 4;

class COrderBlock : public CObject {
public:
   int direction;
   datetime time;
   double high;
   double low;
   bool traded;

   string rectName;  
   string tradeRectName; 

   COrderBlock(int dir, datetime t, double h, double l) {
      direction = dir;
      time = t;
      high = h;
      low = l;
      traded = false;
      rectName = "";
      tradeRectName = "";
      
   }

   void draw(datetime tmS, datetime tmE, color clr) {
      rectName = "OB REC" + TimeToString(time);
      ObjectCreate(0, rectName, OBJ_RECTANGLE, 0, time, low, tmS, high);
      ObjectSetInteger(0, rectName, OBJPROP_FILL, true);
      ObjectSetInteger(0, rectName, OBJPROP_COLOR, clr);

      tradeRectName = "OB trade" + TimeToString(time);
      ObjectCreate(0, tradeRectName, OBJ_RECTANGLE, 0, tmS, high, tmE, low);
      ObjectSetInteger(0, tradeRectName, OBJPROP_FILL, true);
      ObjectSetInteger(0, tradeRectName, OBJPROP_COLOR, clr);
   }
   
   void removeDrawings() {
      if (ObjectFind(0, rectName) != -1) {
         ObjectDelete(0, rectName); // Delete the main rectangle
      }
      if (ObjectFind(0, tradeRectName) != -1) {
         ObjectDelete(0, tradeRectName); // Delete the trade rectangle
      }
   }
};
// Pointer to CArrayObj

// Declare the dynamic array to hold order blocks
CArrayObj *orderBlocks; 
color OBClr;
datetime T1;
datetime T2;

int OnInit() {
   orderBlocks = new CArrayObj(); // Allocate memory for the array
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason) {
   ObjectsDeleteAll(0, "OB");
   
   // Clear and free the order blocks
   if (orderBlocks != NULL) {
      orderBlocks.Clear(); // This will delete objects inside
      delete orderBlocks; // Free the array memory
      orderBlocks = NULL;
   }
}

void OnTick() {
   if (isNewBar()) {
      static int prevDay = 0;
      
      MqlDateTime structTime;
      TimeCurrent(structTime);
      structTime.min = 0;
      structTime.sec = 0;
      
      structTime.hour = Time1Hstrt;
      datetime timestrt = StructToTime(structTime);
      
      structTime.hour = Time1Hend;
      datetime timend = StructToTime(structTime);
      
      getOrderB();
      double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
      double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

      for (int i = orderBlocks.Total() - 1; i >= 0; i--) {
         COrderBlock *OB = (COrderBlock *)orderBlocks.At(i);

         if (CheckPointer(OB) != POINTER_INVALID && !OB.traded) {
         
            if(OB.direction > 0 && Ask < OB.high){
               double entry = Ask;
               double tp = getHigh(iHighest(_Symbol, PERIOD_CURRENT, MODE_HIGH, iBarShift(_Symbol, PERIOD_CURRENT, OB.time)));
               double sl = NormalizeDouble(OB.low - Mgtn, _Digits);
   
               T2 = getTime(0);
               OB.draw(T1, T2, BullOB);
               trade.Buy(Lots, _Symbol, entry, sl, tp, "OB buy");
               OB.traded = true;
               //OB.removeDrawings();
               orderBlocks.Delete(i); // Delete from array
               delete OB; // Free memory
               
               
            }
         }
         if(CheckPointer(OB) != POINTER_INVALID && !OB.traded){
            if (OB.direction < 0 && Bid > OB.low) {
                  double entry = Bid;
                  double tp = getLow(iLowest(_Symbol, PERIOD_CURRENT, MODE_LOW, iBarShift(_Symbol, PERIOD_CURRENT, OB.time)));
                  double sl = NormalizeDouble(OB.high + Mgtn, _Digits);
      
                  T2 = getTime(0);
                  OB.draw(T1, T2, BearOB);
                  trade.Sell(Lots, _Symbol, entry, sl, tp, "OB sell");
                  OB.traded = true;
                  //OB.removeDrawings();
                  orderBlocks.Delete(i); // Delete from array
                  delete OB; // Free memory
                  

            }
         }
      }
   }
}

void getOrderB(){

   static int prevDay = 0;
   
   MqlDateTime structTime;
   TimeCurrent(structTime);
   structTime.min = 0;
   structTime.sec = 0;
   
   structTime.hour = Time1Hstrt;
   datetime timestrt = StructToTime(structTime);
   
   structTime.hour = Time1Hend;
   datetime timend = StructToTime(structTime);
   
   int visibleBars = (int)ChartGetInteger(0,CHART_VISIBLE_BARS);
         
   for(int i = 1; i <= visibleBars; i++){
      if(getOpen(i) < getClose(i)){ // index is i since the loop starts from i which is = 1 "for(int i = 1)..."
         if(getOpen(i + 2) < getClose(i + 2)){
            if(getOpen(i + 3) > getClose(i + 3) && getOpen(i + 3) < getClose(i + 2)){
               Print("Bullish Order Block confirmed at: ", TimeToString(getTime(i + 2), TIME_DATE||TIME_MINUTES));
               //isBullishOB = true;
               //OB = new COrderBlock();
               int direction = 1;
               datetime time = getTime(i + 3);
               double high = getHigh(i + 3);
               double low = getLow(i + 3);
               isBullishOB = true;
               
               OBClr = isBullishOB ? BullOB : BearOB;
               
               // specify strt time
               T1 = time;
               // reset BULLOB flag
               isBullishOB = false;
               // crucial
               COrderBlock *newOB = new COrderBlock(direction, time, high, low);
               orderBlocks.Add(newOB);
               break;
               
               //delete newOB;
            }
         }
      }
      if(getOpen(i) > getClose(i)){
         if(getOpen(i + 2) > getClose(i + 2)){
            if(getOpen(i + 3) < getClose(i + 3) && getOpen(i + 3) < getClose(i + 2)){
               Print("Bearish Order Block confirmed at: ", TimeToString(getTime(i + 2), TIME_DATE||TIME_MINUTES));
               //isBearishOB = true;
               //OB = new COrderBlock();
               int direction = -1;
               datetime time = getTime(i + 3);
               double high = getHigh(i + 3);
               double low = getLow(i + 3);
               isBearishOB = true;
               
               OBClr = isBearishOB ? BearOB : BullOB;
               
               T1 = time;
               
               // reset the BEAROB flag
               isBearishOB = false;
               // crusssial
               COrderBlock *newOB = new COrderBlock(direction, time, high, low);
               orderBlocks.Add(newOB);
               break;
               
               //delete newOB;
            }
         }
      }
    }
      
}

double getHigh(int index) {
    return iHigh(_Symbol, _Period, index);
}

double getLow(int index) {
    return iLow(_Symbol, _Period, index);
}

double getOpen(int index){
   return iOpen(_Symbol, _Period, index);
}

double getClose(int index){
   return iClose(_Symbol, _Period, index);
}

datetime getTime(int index) {
    return iTime(_Symbol, _Period, index);
}

bool isNewBar() {
   // Memorize the time of opening of the last bar in the static variable
   static datetime last_time = 0;
   
   // Get current time
   datetime lastbar_time = (datetime)SeriesInfoInteger(Symbol(), Period(), SERIES_LASTBAR_DATE);

   // First call
   if (last_time == 0) {
      last_time = lastbar_time;
      return false;
   }

   // If the time differs (new bar)
   if (last_time != lastbar_time) {
      last_time = lastbar_time;
      return true;
   }

   // If no new bar, return false
   return false;
}

void deler(){
   static int prevDay = 0;
   
   MqlDateTime structTime;
   TimeCurrent(structTime);
   structTime.min = 0;
   structTime.sec = 0;
   
   structTime.hour = Time1Hstrt;
   datetime timestrt = StructToTime(structTime);
   
   structTime.hour = Time1Hend;
   datetime timend = StructToTime(structTime);

}

前回の記事では、このコードの基本機能と設計について解説しました。本システムは、「オーダーブロック」と呼ばれる特定のローソク足パターンを識別して取引するアルゴリズム取引戦略を実装しており、市場の反転ポイントを示唆する可能性があると考えられています。この戦略はエキスパートアドバイザー(EA)として構築されており、プライスアクション分析と自動売買を組み合わせたものです。コードは、COrderBlockクラスを用いたオブジェクト指向プログラミングを採用し、ローソク足パターンに関連する重要なデータ(タイムスタンプ、価格範囲、方向)を保持し、チャート上へのビジュアル描画も管理します。動的配列CArrayObjにより、アクティブなオーダーブロックを効率的に管理し、複数のチャートインスタンスでもリアルタイムにパターンを監視できます。

getOrderB関数は、過去のローソク足をスキャンし、特定の強気/弱気パターンを認識することでパターン検出をおこないます。たとえば、1本の弱気ローソク足の後に3本の強気ローソク足が続くと、強気のオーダーブロックと判断されます(弱気はその逆)。検出されたパターンは、方向フラグ(強気=1、弱気=-1)を持つCOrderBlockオブジェクトとして生成され、配列に格納されます。さらに、ユーザーが設定可能な時間フィルター(Time1Hstrt、Time1Hend)を使用して、特定の取引時間帯に絞ってパターンの有効性を高めています。

新しいローソク足の生成はisNewBar関数で検出され、EAはOnTick関数内でアクティブなオーダーブロックを処理します。強気パターンに対しては、価格がオーダーブロックの高値をブレイクした際に買いポジションをエントリーし、ストップロスはパターンの安値からマージン(Mtgn)を引いた位置に設定されます。弱気パターンでは、安値を割り込んだ際に売りエントリーし、ストップは高値の上に設定されます。ポジション管理にはCTradeを使用し、利確水準は直近のスイングハイ/スイングローから算出されます。取引が実行されると、関連するオーダーブロックとチャート上の描画が削除され、同じシグナルの重複を防ぎます。

このシステムには複数の安全機構が組み込まれています。ストップロス距離はブローカーの小数点桁数に応じて正規化され、ポジションサイズはLotsで固定されます。チャート上に描画されるカラー矩形は、戦略の透明性と検証可能性を高めます。ストップロス(StopLoss)、利益マージン(Mtgn)、取引セッションの時間帯など、主要パラメータは入力変数としてユーザーが自由にカスタマイズ可能です。このコードは完全自動化を目指しつつも、ブローカー特有の制約(最小ストップ距離やスプレッドなど)に対応し、裁量要素も取り入れた設計となっています。

Pythonバージョン

最初におこなうべきは過去の市場データの取得です。このデータは、AIモデルのトレーニングや戦略の精度検証に必要不可欠な基盤となります。すでに過去記事でデータの取得方法について説明していますので、そちらを参考にしていただければと思います。もし不明な点がある場合や、手順を忘れてしまった方は、MQL5とデータ処理ライブラリを連携させるための最初のガイドをご覧ください。以下では、単純に履歴データを読み込む部分を示します。

import pandas as pd

# Load historical data
file_path = '/home/int_junkie/Documents/DataVisuals/AI inside MQL5/XAUUSD_H1.csv'
data = pd.read_csv(file_path)

# Display the first few rows and column names
print(data.head())
print(data.columns)

Python版のコードを構築するにあたり、まず重要なのは履歴市場データを効果的に処理する設計をおこなうことです。これはAIモデルのトレーニングにおける基盤となります。最初のステップは、スクリプトが履歴データを取り込み、前処理し、構造化された形式で整理できるデータパイプラインを確立することです。このデータには、始値・高値・安値・終値(OHLC)や出来高、必要に応じてテクニカル指標などの主要な特徴量が含まれます。このように整えられたフォーマットにより、AIモデルは過去の市場の動きから有意義なパターンを学習することが可能になります。

次に、LSTMモデルのトレーニング機能を統合します。LSTMは、時系列データを解析し、長期的な依存関係を捉えるのに適した再帰型ニューラルネットワーク(RNN)の一種です。このトレーニングプロセスは、元のMQL5戦略の売買ロジックに合わせて設計されており、過去のプライスアクションに基づいて取引判断をおこなう能力をAIに学習させます。具体的には、履歴データと対応する売買シグナルをマッピングすることで、LSTMモデルは徐々にその予測精度を高めていきます。これにより、将来的な市場の動きをより正確に予測できるようになります。このような構造化されたアプローチにより、従来のルールベース取引とAIによる意思決定との間のギャップを埋めることができ、取引システムの適応性と精度の向上に大きく寄与します。

import pandas as pd
import numpy as np
from datetime import datetime
from keras.models import Sequential
from keras.layers import LSTM, Dense
import tensorflow as tf

# Constants
LOTS = 0.01
TAKE_PROFIT = 170
STOP_LOSS = 350
MGTN = 0.85
TIME1_HSTRT = 3
TIME1_HEND = 4

# Helper functions
def get_high(data, index):
    return data.iloc[index]['<HIGH>']

def get_low(data, index):
    return data.iloc[index]['<LOW>']

def get_open(data, index):
    return data.iloc[index]['<OPEN>']

def get_close(data, index):
    return data.iloc[index]['<CLOSE>']

def get_time(data, index):
    return data.iloc[index]['DATETIME']  # Combined datetime column

def is_new_bar(current_time, last_time):
    return current_time != last_time

class OrderBlock:
    def __init__(self, direction, time, high, low):
        self.direction = direction
        self.time = time
        self.high = high
        self.low = low
        self.traded = False

def get_order_blocks(data):
    order_blocks = []
    visible_bars = len(data)

    for i in range(1, visible_bars - 3):  # Adjusted to avoid index errors
        if get_open(data, i) < get_close(data, i):  # Bullish condition
            if get_open(data, i + 2) < get_close(data, i + 2):
                if get_open(data, i + 3) > get_close(data, i + 3) and get_open(data, i + 3) < get_close(data, i + 2):
                    print(f"Bullish Order Block confirmed at: {get_time(data, i + 2)}")
                    direction = 1
                    time = get_time(data, i + 3)
                    high = get_high(data, i + 3)
                    low = get_low(data, i + 3)
                    order_blocks.append(OrderBlock(direction, time, high, low))
                    break

        if get_open(data, i) > get_close(data, i):  # Bearish condition
            if get_open(data, i + 2) > get_close(data, i + 2):
                if get_open(data, i + 3) < get_close(data, i + 3) and get_open(data, i + 3) < get_close(data, i + 2):
                    print(f"Bearish Order Block confirmed at: {get_time(data, i + 2)}")
                    direction = -1
                    time = get_time(data, i + 3)
                    high = get_high(data, i + 3)
                    low = get_low(data, i + 3)
                    order_blocks.append(OrderBlock(direction, time, high, low))
                    break

    return order_blocks

def simulate_trading(data, order_blocks):
    trades = []
    last_time = None

    for i, row in data.iterrows():
        current_time = row['DATETIME']
        if is_new_bar(current_time, last_time):
            last_time = current_time

            bid = row['<CLOSE>']  # Assuming bid price is close price
            ask = row['<CLOSE>']  # Assuming ask price is close price

            for ob in order_blocks:
                if not ob.traded:
                    if ob.direction > 0 and ask < ob.high:  # Buy condition
                        entry = ask
                        tp = data.iloc[:i]['<HIGH>'].max()  # Take profit as highest high
                        sl = ob.low - MGTN  # Stop loss
                        trades.append({
                            'time': current_time,
                            'direction': 'buy',
                            'entry': entry,
                            'tp': tp,
                            'sl': sl
                        })
                        ob.traded = True

                    if ob.direction < 0 and bid > ob.low:  # Sell condition
                        entry = bid
                        tp = data.iloc[:i]['<LOW>'].min()  # Take profit as lowest low
                        sl = ob.high + MGTN  # Stop loss
                        trades.append({
                            'time': current_time,
                            'direction': 'sell',
                            'entry': entry,
                            'tp': tp,
                            'sl': sl
                        })
                        ob.traded = True

    return trades

このコードは、オーダーブロック検出に基づいた取引戦略を実装し、過去の市場データを使用した取引シミュレーション(バックテスト)をおこなうものです。まず、Pandasによるデータ操作、NumPyによる数値計算、そして将来的なAI統合を視野に入れたKeras/TensorFlowのインポートなど、必要なライブラリを読み込みます。スクリプトは、ロットサイズ(LOTS)、利益確定(TAKE_PROFIT)、損失確定(STOP_LOSS)、リスク管理係数(MGTN)などの主要な取引パラメータを定義します。ヘルパー関数では、データセットから始値、高値、安値、終値、およびタイムスタンプなどの価格情報の抽出をおこない、履歴データへ効率的かつ構造的にアクセスできるようにします。次に、OrderBlockクラスが定義され、検出された強気・弱気のオーダーブロックに関する情報(時間、高値、安値、方向)を格納します。オーダーブロックとは、機関投資家などが大口注文を出したとされる価格帯であり、プライスアクショントレーディングにおいて非常に重要な領域です。

get_order_blocks関数は、過去の価格データを走査し、一連の強気または弱気のローソク足パターンに基づいて潜在的なオーダーブロックを検出します。パターンの変化点を認識し、その時間、高値、安値を記録します。オーダーブロックが特定された後、simulate_trading関数が実行され、シミュレーショントレード(仮想取引)をおこないます。この関数は履歴データを順に走査し、新しいローソク足が出現したかどうか、価格条件が売買シグナルに一致しているかをチェックします。条件が満たされた場合、エントリープライス、利確、損切りを過去の高値・安値に基づいて動的に設定し、取引を記録します。この設計により、戦略のバックテストが可能となり、AIによる取引最適化を次のステップとして組み込むための土台が整います。

# Columns: ['<DATE>', '<TIME>', '<OPEN>', '<HIGH>', '<LOW>', '<CLOSE>']
data = pd.read_csv('/home/int_junkie/Documents/DataVisuals/AI inside MQL5/XAUUSD_H1.csv', delimiter='\t')

# Combine DATE and TIME into a single DATETIME column
data['DATETIME'] = pd.to_datetime(data['<DATE>'] + ' ' + data['<TIME>'])

# Drop the original DATE and TIME columns
data.drop(columns=['<DATE>', '<TIME>'], inplace=True)

# Step 1: Detect order blocks
order_blocks = get_order_blocks(data)

# Step 2: Simulate trading based on order blocks
trades = simulate_trading(data, order_blocks)

マージ処理の完了後、元の日時列は削除され、データセットはクリーンな状態に整理されます。次に、スクリプトは呼び出しget_order_blocks(data)によって、価格データをスキャンして強気・弱気のオーダーブロックを検出します。これらは、価格の大きな反転や機関投資家による注文が入ったと考えられる重要な領域です。オーダーブロックが検出された後は、simulate_trading(data, order_blocks)を実行し、バックテストをおこないます。この関数では、過去の価格変動に基づき、どのタイミングで市場がオーダーブロックの条件を満たしたかを確認し、エントリー価格、利確(テイクプロフィット)、損切り(ストップロス)のルールに基づいて、仮想的な売買を実行します。このプロセスは、過去のプライスアクションに基づいて戦略の有効性を検証するものです。

# Features: Historical OHLC data
# Labels: Buy (1), Sell (-1), Hold (0)
labels = []
for i, row in data.iterrows():
    label = 0  # Hold by default
    for trade in trades:
        if trade['time'] == row['DATETIME']:
            label = 1 if trade['direction'] == 'buy' else -1
    labels.append(label)

data['label'] = labels

# Step 4: Train LSTM model (example using Keras)
from keras.models import Sequential
from keras.layers import LSTM, Dense

# Prepare data for LSTM
def create_sequences(data, seq_length):
    X, y = [], []
    for i in range(len(data) - seq_length):
        X.append(data.iloc[i:i + seq_length][['<OPEN>', '<HIGH>', '<LOW>', '<CLOSE>']].values)
        y.append(data.iloc[i + seq_length]['label'])
    return np.array(X), np.array(y)

seq_length = 50  # Sequence length for LSTM
X, y = create_sequences(data, seq_length)

# Build LSTM model
model = Sequential()
model.add(LSTM(50, input_shape=(seq_length, 4)))  # 4 features: open, high, low, close
model.add(Dense(1, activation='tanh'))  # Output: -1 (sell), 0 (hold), 1 (buy)
model.compile(optimizer='adam', loss='mse')

# Train the model
model.fit(X, y, epochs=20, batch_size=32)

# Save the model
model.save('lstm_trading_model.h5')


出力


このコードセグメントは、過去の価格データを用いて取引判断を予測するためのLSTMモデルをトレーニングします。データセットには3つのラベルが付与されており、1(買い)、-1(売り)、0(様子見)を表します。ラベルは、過去のタイムスタンプを順に確認し、特定の時刻に取引があった場合はその取引方向を反映し、それ以外はデフォルトで0(無操作)となります。これにより、過去の市場データのシーケンスとそれに続く取引アクションの関連性を学習する、教師あり学習の枠組みが構築されます。

LSTMのトレーニングに際しては、データを50ステップのOHLC(始値、高値、安値、終値)シーケンスに再構成します。各シーケンスが入力として用いられ、次の時間ステップにおけるラベルを予測する形式です。モデル構造は以下の通りです。

  • 入力の4特徴量(OHLC)から時系列パターンを解析するLSTM層(50ユニット)
  • tanh活性化関数を用いた全結合出力層で、-1から1の範囲で予測値を生成

トレーニングはAdamオプティマイザー、平均二乗誤差(MSE)損失関数を使用し、20エポック実行されます。学習終了後、モデルはlstm_trading_model.h5として保存され、リアルタイムでの売買シグナル生成に活用できる準備が整います。


モデルのデプロイ

LSTMモデルを.h5ファイルとしてシリアライズした後、次の段階はこのモデルをMQL5エコシステム内で運用可能にすることです。MQL5はPythonとの直接的な統合をサポートしていないため、Pythonの機械学習フレームワークとMQL5のネイティブな取引インフラストラクチャの間に相互運用層を構築する必要があります。一般的な解決策としては、軽量なフレームワーク(FlaskやFastAPIなど)を使用してPythonベースのマイクロサービスをデプロイし、学習済みモデルをホストする方法があります。このサーバーは予測用のエンドポイントとして機能し、MQL5からフォーマットされた市場データを受け取り、LSTMによる推論を実行し、リアルタイムで売買シグナルを返します。MQL5側では、EAがWebRequest APIを利用して連続した価格データをこのエンドポイントに送信し、JSON形式で返ってくるレスポンスを解析します。これにより、生の予測結果が実行可能な取引アクションへと変換されます。

このブリッジが正常に構築された後は、実運用戦略への統合が焦点となります。EAは、設定可能な間隔で選別されたデータバッチ(例:50本のOHLCデータ)を推論サーバーへ自動的に送信します。Pythonサービスはこの入力を前処理し、LSTMアーキテクチャによるテンソル演算を通じて、確率付きの取引指令(買い/売り/様子見)を返します。これらのシグナルはEAの意思決定パイプラインに取り込まれ、事前定義されたリスクパラメータ(動的なストップロス閾値、利益目標比率、ポジションサイズ算出アルゴリズムなど)と組み合わせて、管理された取引を実行します。運用上のリスクを軽減するために、段階的なロールアウトを実施してください。まずはサンドボックス化されたデモ環境でシステムを検証し、推論の遅延やモデルドリフトを継続的に監視します。また、予測異常やサーバー停止時にも機能を維持できるよう、テクニカル指標ベースの戦略へ自動で切り替えるバックアッププロトコルを組み込むことも推奨されます。


結論

本プロジェクトでは、既存のMQL5取引戦略に対して、長短期記憶(LSTM)ニューラルネットワークを活用したAIによる意思決定プロセスを統合し、戦略を高度化しました。まず、MQL5戦略の中核ロジックをPythonに移植し、過去のOHLCデータを用いてその挙動を再現しました。次に、オーダーブロックなどの主要なトレードシグナルを特定し、シミュレーションを通じてラベル付きのデータを生成し、AIモデルの学習に使用しました。その後、LSTMモデルを過去の価格データの時系列に基づいて訓練し、次のマーケットの動きが「買い」「売り」「様子見」のいずれであるかを予測するようにしました。最終的に、モデルは.h5形式で保存され、ライブまたは半自動売買に向けたデプロイが可能な状態になりました。

従来のルールベース戦略にAIを統合することで、トレーダーは非常に強力な利点を得られます。固定条件に従う静的ロジックとは異なり、LSTMモデルは複雑な価格変動パターンを学習し、時間とともに変化する市場のダイナミクスに適応できます。これにより、戦略はより柔軟で、精度が向上し、静的なシステムが誤認しがちなシグナルに惑わされにくくなります。トレーダーは、テクニカルルールの構造的な信頼性と、機械学習の適応性・学習能力という「2つの世界の良いとこ取り」をしたシステムの恩恵を受けることができます。

このようなハイブリッドアプローチは、エントリーおよびイグジット判断の質を向上させるだけでなく、リアルタイムでのインテリジェントなリスク管理を可能にします。テクニカルルールの構造的な信頼性と、機械学習による適応性・学習能力を融合することで、トレーダーにとって最良の要素を兼ね備えた取引環境を実現します。固定条件に従う静的ロジックとは異なり、LSTMモデルは複雑な価格変動パターンを学習し、時間とともに変化する市場のダイナミクスに適応できます。これにより、戦略はより柔軟で、精度が向上し、静的なシステムが誤認しがちなシグナルに惑わされにくくなります。トレーダーは、テクニカルルールの構造的な信頼性と、機械学習の適応性・学習能力という「2つの世界の良いとこ取り」をしたシステムの恩恵を受けることができます。このハイブリッドアプローチは、エントリーとエグジットの決定を改善するだけでなく、リアルタイム取引におけるよりインテリジェントなデータ主導型のリスク管理への扉を開きます。

ファイル名
説明
FIB_OB.mq5 オリジナルのMQL5戦略を含むファイル
FIB_OB to AI.ipynb
戦略ロジックを変換し、モデルをトレーニングして保存するためのNotebookを含むファイル
XAUUSD_H1.csv
XAUUSDの過去の価格データを含むファイル


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

添付されたファイル |
最後のコメント | ディスカッションに移動 (1)
malky3200
malky3200 | 28 4月 2025 において 10:25
質問です。
AIに継続的に学習させることは可能ですか?
初心者からエキスパートへ:ローソク足のプログラミング 初心者からエキスパートへ:ローソク足のプログラミング
この記事では、MQL5プログラミングの第一歩を、完全な初心者でも理解できるように解説します。よく知られているローソク足パターンを、実際に機能するカスタムインジケーターへと変換する方法を紹介します。ローソク足パターンは、実際の価格変動を反映し、市場の転換を示唆するため、非常に有用です。チャートを目視で確認してパターンを探す手法ではミスや非効率が生じやすいため、この記事では、パターンを自動的に識別・ラベル付けしてくれるインジケーターを作成する方法を説明します。その過程で、インデックス(索引)、時系列、ATR(市場の変動性に応じた精度向上のため)などの重要な概念についても解説し、今後のプロジェクトで再利用可能なカスタムローソク足パターンライブラリの開発にも触れていきます。
プライスアクション分析ツールキットの開発(第20回):External Flow (IV) — Correlation Pathfinder プライスアクション分析ツールキットの開発(第20回):External Flow (IV) — Correlation Pathfinder
Correlation Pathfinderは、「プライスアクション分析ツールキット開発」連載の一環として、通貨ペアの動的な関係を理解するための新しいアプローチを提供します。このツールはデータの収集と分析を自動化し、EUR/USDやGBP/USDなどのペアがどのように連動して動いているかを可視化します。リスク管理を強化し、より効果的にチャンスを捉えるための実用的かつリアルタイムな情報で、取引戦略のレベルを引き上げましょう。
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法 エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
この記事では、MT4において複数のEAの衝突をさける方法を扱います。ターミナルの操作、MQL4の基本的な使い方がわかる人にとって、役に立つでしょう。
オープニングレンジブレイクアウト日中取引戦略の解読 オープニングレンジブレイクアウト日中取引戦略の解読
オープニングレンジブレイクアウト(ORB)戦略は、市場が開いた直後に形成される初期の取引レンジが、買い手と売り手が価値に合意する重要な価格レベルを反映しているという考えに基づいて構築されています。特定のレンジを上抜けまたは下抜けするブレイクアウトを特定することで、市場の方向性が明確になるにつれて発生することが多いモメンタムを利用し、トレーダーは利益を狙うことができます。本記事では、Concretum Groupの論文から応用した3つのORB戦略を紹介します。