EA開発もここまできたか…ついにAIでプログラミングする時代に突入し、EAもAIで作れそうな時代になってきました。
ChatGPTを利用して、トレード戦略のアイデアや必要な情報をAIに聞きながら、EAの開発ができそうなので実際に試して作ってみた結果をご報告いたします。
ちなみに、今回はChatGPTの有料版であるGPT4を使っています。
ChatGPTを使ってMT4のEAを設計するステップ
さっそくですが、以下のステップにしたがって、ChatGPTを使ってMT4のEAを設計していきましょう。
トレーディング戦略のアイデアを明確にする


まず始めに、どのようなトレーディング戦略をEAに実装したいかを明確にしましょう。具体的な目標や戦略を決めると、目的のEAが完成しやすいです。
たとえば、トレンドフォローや逆張りか、損切りはどのくらいか、通貨ペアは何かなどです。
ChatGPTを活用して必要な情報を集める
戦略がイメージしづらい場合、ChatGPTを使って、トレーディング戦略に関連する情報やアイデアを集めます。たとえば、利用したいインジケーターやパラメータの最適化方法、リスク管理手法などを調べられます。
また、ChatGPTは他のトレーダーの意見や経験にもアクセスできるため、新しいアイデアを得たりできます。
トレード戦略のルールを決定する
ChatGPTから得た情報をもとに、トレード戦略の具体的なルールを決定します。
エントリーやエグジットのタイミング、ストップロスやテイクプロフィットの設定、ポジションサイズの調整など、EAがどのように動作するかを定めましょう。戦略のルールが決まったら、次のステップであるプログラミングに進みましょう。
試しに思いつくままにChatGPTに命令をして、EAを作成してもらってみました。

そして、できたソースコードが以下になります。
//+------------------------------------------------------------------+
//| TrendFollowingEA.mq4 |
//| Copyright © 2023, Your Name Here |
//| example.com |
//+------------------------------------------------------------------+
// Input parameters
input int FastMA_Period = 10;
input int SlowMA_Period = 20;
input int ADX_Period = 14;
input double RiskPercentage = 2; // Risk % of the account balance per trade
input double StopLoss_ATR_Multiplier = 2; // Stop Loss in terms of ATR
input double TakeProfit_ATR_Multiplier = 4; // Take Profit in terms of ATR
input int ATR_Period = 14; // ATR period for stop loss and take profit calculation
// Global variables
int FastMA_Handle, SlowMA_Handle, ADX_Handle, ATR_Handle;
double Point;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Set up handles for the indicators
FastMA_Handle = iMA(_Symbol, PERIOD_H1, FastMA_Period, 0, MODE_SMA, PRICE_CLOSE);
SlowMA_Handle = iMA(_Symbol, PERIOD_H1, SlowMA_Period, 0, MODE_SMA, PRICE_CLOSE);
ADX_Handle = iADX(_Symbol, PERIOD_H1, ADX_Period);
ATR_Handle = iATR(_Symbol, PERIOD_H1, ATR_Period);
// Get the point value for the current symbol
Point = _Point;
// If any errors occur during initialization, return an error code
if(FastMA_Handle == INVALID_HANDLE || SlowMA_Handle == INVALID_HANDLE ||
ADX_Handle == INVALID_HANDLE || ATR_Handle == INVALID_HANDLE)
{
Print("Error: Unable to create indicator handles.");
return INIT_FAILED;
}
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Release the indicator handles
IndicatorRelease(FastMA_Handle);
IndicatorRelease(SlowMA_Handle);
IndicatorRelease(ADX_Handle);
IndicatorRelease(ATR_Handle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Check if there is an open order
if(PositionSelect(_Symbol))
{
// Check if the market conditions have changed and if it's necessary to close the position
if(CheckExitConditions())
{
PositionClose(_Symbol);
}
}
else
{
// If no open positions, check for entry conditions and place a new order
int orderType = CheckEntryConditions();
if(orderType != -1)
{
PlaceOrder(orderType);
}
}
}
//+------------------------------------------------------------------+
//| Check for entry
//+------------------------------------------------------------------+
int CheckEntryConditions()
{
double FastMA_Current = iMAOnArray(MABuffer,0,0);
double FastMA_Previous = iMAOnArray(MABuffer,0,1);
double SlowMA_Current = iMAOnArray(MABuffer,1,0);
double SlowMA_Previous = iMAOnArray(MABuffer,1,1);
double ADX_Main = iADXOnArray(ADXBuffer,0,0);
double ADX_Positive = iADXOnArray(ADXBuffer,1,0);
double ADX_Negative = iADXOnArray(ADXBuffer,2,0);
// Buy entry condition: Fast MA crosses above Slow MA and ADX indicates a strong trend
if(FastMA_Current > SlowMA_Current && FastMA_Previous <= SlowMA_Previous && ADX_Main > 25 && ADX_Positive > ADX_Negative)
{
return OP_BUY;
}
// Sell entry condition: Fast MA crosses below Slow MA and ADX indicates a strong trend
else if(FastMA_Current < SlowMA_Current && FastMA_Previous >= SlowMA_Previous && ADX_Main > 25 && ADX_Positive < ADX_Negative)
{
return OP_SELL;
}
// No entry conditions met
else
{
return -1;
}
}
//+------------------------------------------------------------------+
//| Check for exit conditions |
//+------------------------------------------------------------------+
bool CheckExitConditions()
{
// Retrieve the current position type
int positionType = PositionGetInteger(POSITION_TYPE);
// Calculate the moving averages
double FastMA_Current = iMAOnArray(MABuffer,0,0);
double SlowMA_Current = iMAOnArray(MABuffer,1,0);
// Check if the moving averages have crossed in the opposite direction
if((positionType == POSITION_TYPE_BUY && FastMA_Current < SlowMA_Current) ||
(positionType == POSITION_TYPE_SELL && FastMA_Current > SlowMA_Current))
{
return true;
}
else
{
return false;
}
}
//+------------------------------------------------------------------+
//| Place an order with appropriate stop loss, take profit, and lot size |
//+------------------------------------------------------------------+
void PlaceOrder(int orderType)
{
// Calculate stop loss and take profit based on ATR
double ATR = iATR(_Symbol, PERIOD_H1, ATR_Period, 0);
double stopLoss = ATR * StopLoss_ATR_Multiplier;
double takeProfit = ATR * TakeProfit_ATR_Multiplier;
// Calculate the entry price, stop loss and take profit levels
double entryPrice = (orderType == OP_BUY) ? Ask : Bid;
double stopLossLevel = (orderType == OP_BUY) ? entryPrice - stopLoss : entryPrice + stopLoss;
double takeProfitLevel = (orderType == OP_BUY) ? entryPrice + takeProfit : entryPrice - takeProfit;
// Calculate the appropriate lot size based on risk management
double lotSize = CalculateLotSize(stopLoss);
// Place the order
ulong ticket;
if(orderType == OP_BUY)
{
ticket = OrderSend(_Symbol, OP_BUY, lotSize, Ask, 10, stopLossLevel, takeProfitLevel);
}
else
{
ticket = OrderSend(_Symbol, OP_SELL, lotSize, Bid, 10, stopLossLevel, takeProfitLevel);
}
// Checkfor errors and print a message if necessary
if(ticket == 0)
{
Print("Error placing order: ", GetLastError());
}
else
{
Print("Order placed successfully: Ticket #", ticket);
}
}
//+------------------------------------------------------------------+
//| Calculate the lot size based on risk management |
//+------------------------------------------------------------------+
double CalculateLotSize(double stopLoss)
{
double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
double riskAmount = accountBalance * (RiskPercentage / 100);
double lotSize = riskAmount / (stopLoss * Point * AccountInfoInteger(ACCOUNT_LEVERAGE));
// Adjust the lot size to the minimum and maximum lot size allowed by the broker
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
lotSize = NormalizeDouble(lotSize, 2);
lotSize = MathMin(MathMax(lotSize, minLot), maxLot);
return lotSize;
}
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[])
{
ArraySetAsSeries(close, true);
// Calculate the moving averages
int fastShift = 0, slowShift = 0;
while(fastShift < rates_total && slowShift < rates_total)
{
MABuffer[0][fastShift] = iMAOnArray(close, FastMA_Period, fastShift);
MABuffer[1][slowShift] = iMAOnArray(close, SlowMA_Period, slowShift);
fastShift++;
slowShift++;
}
// Calculate the ADX values
int adxShift = 0;
while(adxShift < rates_total)
{
ADXBuffer[0][adxShift] = iADXOnArray(high, low, close, ADX_Period, adxShift, MODE_MAIN);
ADXBuffer[1][adxShift] = iADXOnArray(high, low, close, ADX_Period, adxShift, MODE_PLUSDI);
ADXBuffer[2][adxShift] = iADXOnArray(high, low, close, ADX_Period, adxShift, MODE_MINUSDI);
adxShift++;
}
return rates_total;
}
//+------------------------------------------------------------------+
できたソースコードをそのままコンパイルしてみると、コンパイルエラーとなってしまいました。
どうやら生成してもらったソースコードをそのまま使用するのは難しそうです。
コーディングのポイントとテスト
さきほどChatGPTにEAのソースコードを丸々作成してもらいましたが、もうちょっと工夫して作成していきましょう。
先ほどは制約を入れすぎたので、絞ってからまずはEAの原型となるソースを作成してもらいます。

//+------------------------------------------------------------------+
//| TrendFollowingEA.mq4 |
//| Copyright 2023, Company-Name.com |
//| Your Name Here |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Company-Name.com"
#property link "http://www.company-name.com"
#property version "1.00"
#property strict
// Input parameters
extern double StopLoss = 50;
extern double TakeProfit = 100;
extern int Slippage = 3;
extern int MagicNumber = 12345;
extern double LotSize = 0.1;
extern int FastEMA = 12;
extern int SlowEMA = 26;
extern int SignalEMA = 9;
int OnInit()
{
// Initialization
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
// Deinitialization
}
void OnTick()
{
double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
datetime CurrentTime = TimeCurrent();
// Check if there are open orders for this EA
bool hasOpenOrders = false;
for(int i = 0; i < OrdersTotal(); i++) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderSymbol() == _Symbol && OrderMagicNumber() == MagicNumber) {
hasOpenOrders = true;
break;
}
}
}
if(!hasOpenOrders) {
// Calculate EMA values
double fastEMA = iMA(_Symbol, PERIOD_H1, FastEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double slowEMA = iMA(_Symbol, PERIOD_H1, SlowEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
// Calculate MACD values
double mainMACD = iMACD(_Symbol, PERIOD_H1, FastEMA, SlowEMA, SignalEMA, PRICE_CLOSE, MODE_MAIN, 1);
double signalMACD = iMACD(_Symbol, PERIOD_H1, FastEMA, SlowEMA, SignalEMA, PRICE_CLOSE, MODE_SIGNAL, 1);
// Determine the trade signal
bool buySignal = fastEMA > slowEMA && mainMACD > signalMACD;
bool sellSignal = fastEMA < slowEMA && mainMACD < signalMACD;
// Open buy order
if(buySignal) {
double buyStopLoss = Bid - StopLoss * _Point;
double buyTakeProfit = Bid + TakeProfit * _Point;
OrderSend(_Symbol, OP_BUY, LotSize, Ask, Slippage, buyStopLoss, buyTakeProfit, "Buy Order", MagicNumber, 0, clrBlue);
}
// Open sell order
if(sellSignal) {
double sellStopLoss = Ask + StopLoss * _Point;
double sellTakeProfit = Ask - TakeProfit * _Point;
OrderSend(_Symbol, OP_SELL, LotSize, Bid, Slippage, sellStopLoss, sellTakeProfit, "Sell Order", MagicNumber, 0, clrRed);
}
}
}
//+------------------------------------------------------------------+
今度はコンパイルが上手く通りましたが、このままだとバックテストは撃沈でした。
ChatGPTを活用してトレードパフォーマンスを向上させる方法
先ほどはバックテストが撃沈でしたが、もうちょっと改良をしてもらいましょう。
以下の命令をしてはバックテストを繰り返していきます。

何回か繰り返した結果のコードとバックテストです。
//+------------------------------------------------------------------+
//| TrendFollowingEA.mq4 |
//| Copyright 2023, Company-Name.com |
//| Your Name Here |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Company-Name.com"
#property link "http://www.company-name.com"
#property version "1.00"
#property strict
// Input parameters
extern double StopLoss = 50;
extern double TakeProfit = 100;
extern int Slippage = 3;
extern int MagicNumber = 12345;
extern double FixedLotSize = 0.1;
extern double RiskPercentage = 2.0;
extern int FastEMA = 12;
extern int SlowEMA = 26;
extern int SignalEMA = 9;
extern int RSI_Period = 14;
extern int RSI_Level = 50;
extern int ATR_Period = 14;
int OnInit()
{
// Initialization
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
// Deinitialization
}
void OnTick()
{
double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
datetime CurrentTime = TimeCurrent();
// Check if there are open orders for this EA
bool hasOpenOrders = false;
for(int i = 0; i < OrdersTotal(); i++) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderSymbol() == _Symbol && OrderMagicNumber() == MagicNumber) {
hasOpenOrders = true;
break;
}
}
}
if(!hasOpenOrders) {
// Calculate EMA values
double fastEMA = iMA(_Symbol, PERIOD_H1, FastEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double slowEMA = iMA(_Symbol, PERIOD_H1, SlowEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double fastEMA_previous = iMA(_Symbol, PERIOD_H1, FastEMA, 0, MODE_EMA, PRICE_CLOSE, 2);
double slowEMA_previous = iMA(_Symbol, PERIOD_H1, SlowEMA, 0, MODE_EMA, PRICE_CLOSE, 2);
// Calculate MACD values
double mainMACD = iMACD(_Symbol, PERIOD_H1, FastEMA, SlowEMA, SignalEMA, PRICE_CLOSE, MODE_MAIN, 1);
double signalMACD = iMACD(_Symbol, PERIOD_H1, FastEMA, SlowEMA, SignalEMA, PRICE_CLOSE, MODE_SIGNAL, 1);
// Calculate RSI values
double currentRSI = iRSI(_Symbol, PERIOD_H1, RSI_Period, PRICE_CLOSE, 1);
double previousRSI = iRSI(_Symbol, PERIOD_H1, RSI_Period, PRICE_CLOSE, 2);
// Calculate ATR values
double currentATR = iATR(_Symbol, PERIOD_H1, ATR_Period, 1);
// Determine the trade signal
bool buySignal = fastEMA > slowEMA && fastEMA_previous <= slowEMA_previous && mainMACD > signalMACD && currentRSI > RSI_Level && previousRSI <= RSI_Level;
bool sellSignal = fastEMA < slowEMA && fastEMA_previous >= slowEMA_previous && mainMACD < signalMACD && currentRSI < RSI_Level && previousRSI >= RSI_Level;
// Calculate the dynamic lot size based on the account balance and risk percentage
double dynamicLotSize = NormalizeDouble((AccountBalance() * (RiskPercentage / 100)) / (StopLoss * 10), 2);
// Calculate dynamic StopLoss and TakeProfit based on ATR
double dynamicStopLoss = StopLoss * _Point + currentATR;
double dynamicTakeProfit = TakeProfit * _Point + currentATR;
// Open buy order
if(buySignal) {
double buyStopLoss = Bid - dynamicStopLoss;
double buyTakeProfit = Bid + dynamicTakeProfit;
OrderSend(_Symbol, OP_BUY, MathMax(FixedLotSize, dynamicLotSize), Ask, Slippage, buyStopLoss, buyTakeProfit, "Buy Order", MagicNumber, 0, clrBlue);
}
// Open sell order
if(sellSignal) {
double sellStopLoss = Ask + dynamicStopLoss;
double sellTakeProfit = Ask - dynamicTakeProfit;
OrderSend(_Symbol, OP_SELL, MathMax(FixedLotSize, dynamicLotSize), Bid, Slippage, sellStopLoss, sellTakeProfit, "Sell Order", MagicNumber, 0, clrRed);
}
}
}

パラメータの最適化
EAの成功は、適切なパラメータ設定に大きく依存します。ChatGPTは、多様な市場状況に対応するために、最適なパラメータ設定を見つけ出す手助けをします。AIに過去の市場データや現在のトレンドを入力し、パラメータの適切な範囲を提案してもらいましょう。


最適化の目安がわかりました、合っているのかは不明ですが、手動で最適化をしていきます。最適化作業だけはどうしても手動になってしまいます。
最終的にできたEA
適当に最適化し、今回できたEAをバックテストしてみます。まだ本番では使えなさそうですが、1時間もかからず、ここまでのEAを作れました。恐るべきChatGPT!
今回作ったEA(最適化前)は以下からダウンロード可能です。絶対本番では動かさないでください。

まとめ
ChatGPTを活用してMT4で独自のEAを作成する方法を解説しました。まだ完全にソースコードを作成できないですが、ちょっとずつ工夫しながらChatGPTを活用してEAを作れそうです。