AIでプログラミングChatGPTFX自動売買(EA)の作り方MQL4MQL5

最新のChatGPT(GPT-4)でMT4のEAをMT5のEAに変換することは出来るのか検証

※アフィリエイト広告を利用しています

広告

ChatGPTは、OpenAIによって提供されているチャット型AIです。EA開発に必要なプログラミングスキルも備えていることで知られています。

2023年3月にChatGPTにもGPT-4が実装されたということで、その進化具合をMQL5のプログラミングスキルで比較してみたいと思います。

ちなみに、GPT-4は何かというのをChatGPTに質問してみました。

GPT-4とGPT-3.5の違いを簡潔に教えてください。
GPT-4とGPT-3.5の違いは、GPT-4がより大規模なデータセットで訓練され、文脈理解能力や一貫性、精度が向上している点です。これにより、GPT-4は一般的にGPT-3.5よりも優れたパフォーマンスを発揮します。

なお、以前には別の記事でGPT-3.5でMQL5のコーディングを試してみているのですが、MQL4と比べてMQL5は苦手なようでかなり苦戦しました。

ということで今回は、進化した最新のChatGPT(GPT-4)にMT4用EAをMT5用EAに変換してもらうことにしましょう。

広告

MQL4のコードをMQL5に変換してもらう

今回は、以下の記事で作成したMT4用のEAのコード(MQL4)をインプットにします。

以下の通り、全コードを貼り付けて、ChatGPTにMT5用EAへの変換をお願いしてみます。

インプット:MQL4のコード

以下のMQL4のコードをMQL5に変換してMT5でコンパイルできるようにしてください。

//+------------------------------------------------------------------+
//| nanpin-martin.mq4 |
//| ` Copyright 2022, nanpin-martin.com |
//| "https://nanpin-martin.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, nanpin-martin.com"
#property link "https://nanpin-martin.com/"


//+------------------------------------------------------------------+
//| Inputの設定 |
//+------------------------------------------------------------------+

input double first_lot = 0.01;//初期ロット
input double nanpin_range = 200;//ナンピン幅
input double profit_target = 143;//利益目標
input int magic_number = 10001; //マジックナンバー
static int ticket_number;//チケットナンバー
double slippage = 10;//スリッページ


//+------------------------------------------------------------------+
//| ループ処理 |
//+------------------------------------------------------------------+
void OnTick()
{

//+----変数の定義-----------------------------------------------------+

int cnt;
int current_buy_position;//最新のbuyポジション
int current_sell_position;//最新のsellポジション
int buy_position;//buyポジション数
int sell_position;//sellポジション数
double buy_profit;//buyポジションの含み損益
double sell_profit;//sellポジションの含み損益

//+------------------------------------------------------------------+


//+----ポジションの確認--------------------------------------------------+

buy_position=0;//buyポジション数の初期化
sell_position=0;//sellポジション数の初期化
current_buy_position=-1;//最新buyポジションの初期化
current_sell_position=-1;//最新sellポジションの初期化

for(cnt=0;cnt<OrdersTotal();cnt++)//ポジションの確認
{
if(OrderSelect(cnt,SELECT_BY_POS)==false)continue;
if(OrderMagicNumber()!=magic_number)continue;
if(OrderType()==OP_BUY)
{
current_buy_position=cnt;
buy_position+=1;
buy_profit=buy_profit+OrderProfit();
};//buyポジションの確認

if(OrderType()==OP_SELL)
{
current_sell_position=cnt;
sell_position+=1;
sell_profit=sell_profit+OrderProfit();
};//sellポジションの確認
}

//+------------------------------------------------------------------+


//+----新規エントリー注文------------------------------------------------+

if(buy_position==0)//buyポジションを持っていない場合
{
ticket_number=OrderSend(
Symbol(), //通貨ペア
OP_BUY, //buy:OP_BUY, sell:OP_SELL
first_lot, //ロット数
Ask, //注文価格
slippage, //スリッページ
0, //決済逆指値
0, //決済指値
"first_buy", //注文コメント
magic_number, //マジックナンバー
0, //注文の有効期限
Blue //矢印の色
);
}
if(sell_position==0)//sellポジションを持っていない場合
{
ticket_number=OrderSend(
Symbol(), //通貨ペア
OP_SELL, //buy:OP_BUY, sell:OP_SELL
first_lot, //ロット数
Bid, //注文価格
slippage, //スリッページ
0, //決済逆指値
0, //決済指値
"first_sell", //注文コメント
magic_number, //マジックナンバー
0, //注文の有効期限
Red //矢印の色
);
}

//+------------------------------------------------------------------+


//+----追加エントリー(ナンピン)注文----------------------------------------+

if(buy_position>0) //buyポジションを1つ以上持っている場合
{
OrderSelect(current_buy_position,SELECT_BY_POS); //最新のbuyポジションを選択
if(Ask<(OrderOpenPrice()-nanpin_range*Point)) //現在価格がナンピン幅に達しているか
{
ticket_number=OrderSend(
Symbol(), //通貨ペア
OP_BUY, //buy:OP_BUY, sell:OP_SELL
round(OrderLots()*1.5*100)/100, //ロット数
Ask, //注文価格
slippage, //スリッページ
0, //決済逆指値
0, //決済指値
"nanpin_buy", //注文コメント
magic_number, //マジックナンバー
0, //注文の有効期限
Blue //矢印の色
);
}
}

if(sell_position>0) //sellポジションを1つ以上持っている場合
{
OrderSelect(current_sell_position,SELECT_BY_POS); //最新のsellポジションを選択
if(Bid>(OrderOpenPrice()+nanpin_range*Point)) //現在価格がナンピン幅に達しているか
{
ticket_number=OrderSend(
Symbol(), //通貨ペア
OP_SELL, //buy:OP_BUY, sell:OP_SELL
round(OrderLots()*1.5*100)/100, //ロット数
Bid, //注文価格
slippage, //スリッページ
0, //決済逆指値
0, //決済指値
"nanpin_sell", //注文コメント
magic_number, //マジックナンバー
0, //注文の有効期限
Red //矢印の色
);

}
}

//+------------------------------------------------------------------+


//+----ポジションクローズ注文----------------------------------------------+

if(buy_position>0&&buy_profit>profit_target*buy_position)
{
buyClose(Red);//すべてbuyポジションをクローズ
}

if(sell_position>0&&sell_profit>profit_target*sell_position)
{
sellClose(Blue);//すべてsellポジションをクローズ
}

//+------------------------------------------------------------------+

}

//+------------------------------------------------------------------+
//| ループ処理おわり |
//+------------------------------------------------------------------+


//+------------------------------------------------------------------+
//| ポジションをクローズする関数 |
//+------------------------------------------------------------------+


//+----buyポジションをクローズする関数----------------------------------------+
void buyClose(color clr)
{
int i;
for(i=OrdersTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)
continue;
if(OrderSymbol()!=Symbol()||OrderMagicNumber()!=magic_number)
continue;
if(OrderType()==OP_BUY)
OrderClose(OrderTicket(),OrderLots(),Bid,NormalizeDouble(slippage,0),clr);
}
}

//+------------------------------------------------------------------+


//+----sellポジションをクローズする関数---------------------------------------+
void sellClose(color clr)
{
int i;
for(i=OrdersTotal()-1;i>=0;i--)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)
continue;
if(OrderSymbol()!=Symbol()||OrderMagicNumber()!=magic_number)
continue;
if(OrderType()==OP_SELL)
OrderClose(OrderTicket(),OrderLots(),Ask,NormalizeDouble(slippage,0),clr);
}
}

//+------------------------------------------------------------------+

アウトプット:MQL5のコード

以下の通り、すぐに返事が来ました。

以下のコードは、MQL4コードをMQL5に変換し、MT5でコンパイルできるようにしました。

//+------------------------------------------------------------------+
//| nanpin-martin.mq5 |
//| ` Copyright 2022, nanpin-martin.com |
//| "https://nanpin-martin.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, nanpin-martin.com"
#property link "https://nanpin-martin.com/"
#property version "1.00"
#property strict

//+------------------------------------------------------------------+
//| Inputの設定 |
//+------------------------------------------------------------------+

input double first_lot = 0.01; //初期ロット
input double nanpin_range = 200; //ナンピン幅
input double profit_target = 143; //利益目標
input int magic_number = 10001; //マジックナンバー
static int ticket_number; //チケットナンバー
double slippage = 10; //スリッページ

//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}

//+------------------------------------------------------------------+
//| ループ処理 |
//+------------------------------------------------------------------+
void OnTick()
{

//+----変数の定義-----------------------------------------------------+

int cnt;
int current_buy_position; //最新のbuyポジション
int current_sell_position; //最新のsellポジション
int buy_position; //buyポジション数
int sell_position; //sellポジション数
double buy_profit; //buyポジションの含み損益
double sell_profit; //sellポジションの含み損益

MqlTradeRequest request;
MqlTradeResult result;

//+------------------------------------------------------------------+
//+----ポジションの確認--------------------------------------------------+

buy_position = 0; //buyポジション数の初期化
sell_position = 0; //sellポジション数の初期化
current_buy_position = -1; //最新buyポジションの初期化
current_sell_position = -1; //最新sellポジションの初期化

for(cnt = 0; cnt < PositionsTotal(); cnt++) //ポジションの確認
{
ulong position_ticket = PositionGetTicket(cnt);
if(PositionGetInteger(POSITION_MAGIC) != magic_number)
continue;
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
current_buy_position = cnt;
buy_position++;
buy_profit = buy_profit + PositionGetDouble(POSITION_PROFIT);
}; //buyポジションの確認

if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
{
current_sell_position = cnt;
sell_position++;
sell_profit = sell_profit + PositionGetDouble(POSITION_PROFIT);
}; //sellポジションの確認
}

//+------------------------------------------------------------------+

//+----新規エントリー注文------------------------------------------------+

if(buy_position == 0) //buyポジションを持っていない場合
{
ZeroMemory(request);
request.action = TRADE_ACTION_DEAL;
request.symbol = Symbol();
request.volume = first_lot;
request.type = ORDER_TYPE_BUY;
request.price = NormalizeDouble(Ask, _Digits);
request.sl = 0;
request.tp = 0;
request.deviation = slippage;
request.magic = magic_number;
request.comment = "first_buy";
OrderSend(request, result);
}
if(sell_position == 0) //sellポジションを持っていない場合
{
ZeroMemory(request);
request.action = TRADE_ACTION_DEAL;
request.symbol = Symbol();
request.volume = first_lot;
request.type = ORDER_TYPE_SELL;
request.price = NormalizeDouble(Bid, _Digits);
request.sl = 0;
request.tp = 0;
request.deviation = slippage;
request.magic = magic_number;
request.comment = "first_sell";
OrderSend(request, result);
}

//+------------------------------------------------------------------+

//+----追加エントリー(ナンピン)注文----------------------------------------+

if(buy_position > 0) //buyポジションを1つ以上持っている場合
{
PositionSelectByTicket(PositionGetTicket(current_buy_position)); //最新のbuyポジションを選択
if(Ask < (PositionGetDouble(POSITION_PRICE_OPEN) - nanpin_range * _Point)) //現在価格がナンピン幅に達しているか
{
ZeroMemory(request);
request.action = TRADE_ACTION_DEAL;
request.symbol = Symbol();
request.volume = MathRound(PositionGetDouble(POSITION_VOLUME) * 1.5 * 100) / 100;
request.type = ORDER_TYPE_BUY;
request.price = NormalizeDouble(Ask, _Digits);
request.sl = 0;
request.tp = 0;
request.deviation = slippage;
request.magic = magic_number;
request.comment = "nanpin_buy";
OrderSend(request, result);
}
}

if(sell_position > 0) //sellポジションを1つ以上持っている場合
{
PositionSelectByTicket(PositionGetTicket(current_sell_position)); //最新のsellポジションを選択
if(Bid > (PositionGetDouble(POSITION_PRICE_OPEN) + nanpin_range * _Point)) //現在価格がナンピン幅に達しているか
{
ZeroMemory(request);
request.action = TRADE_ACTION_DEAL;
request.symbol = Symbol();
request.volume = MathRound(PositionGetDouble(POSITION_VOLUME) * 1.5 * 100) / 100;
request.type = ORDER_TYPE_SELL;
request.price = NormalizeDouble(Bid, _Digits);
request.sl = 0;
request.tp = 0;
request.deviation = slippage;
request.magic = magic_number;
request.comment = "nanpin_sell";
OrderSend(request, result);
}
}

//+------------------------------------------------------------------+

//+----ポジションクローズ注文----------------------------------------------+

if(buy_position > 0 && buy_profit > profit_target * buy_position)
{
buyClose(clrRed); //すべてbuyポジションをクローズ
}

if(sell_position > 0 && sell_profit > profit_target * sell_position)
{
sellClose(clrBlue); //すべてsellポジションをクローズ
}

//+------------------------------------------------------------------+

}

//+------------------------------------------------------------------+
//| ループ処理おわり |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| ポジションをクローズする関数 |
//+------------------------------------------------------------------+

//+----buyポジションをクローズする関数----------------------------------------+
void buyClose(color clr)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong position_ticket = PositionGetTicket(i);
if(PositionSelectByTicket(position_ticket) == false)
continue;
if(PositionGetSymbol(position_ticket) != Symbol() || PositionGetInteger(POSITION_MAGIC) != magic_number)
continue;
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
ZeroMemory(request);
request.action = TRADE_ACTION_DEAL;
request.symbol = Symbol();
request.position = position_ticket;
request.type = ORDER_TYPE_SELL;
request.price = NormalizeDouble(Bid, _Digits);
request.volume = PositionGetDouble(POSITION_VOLUME);
request.deviation = slippage;
request.comment = "Close buy position";
request.arrow_color = clr;
OrderSend(request, result);
}
}
}

//+------------------------------------------------------------------+

//+----sellポジションをクローズする関数---------------------------------------+
void sellClose(color clr)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong position_ticket = PositionGetTicket(i);
if(PositionSelectByTicket(position_ticket) == false)
continue;
if(PositionGetSymbol(position_ticket) != Symbol() || PositionGetInteger(POSITION_MAGIC) != magic_number)
continue;
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
{
ZeroMemory(request);
request.action = TRADE_ACTION_DEAL;
request.symbol = Symbol();
request.position = position_ticket;
request.type = ORDER_TYPE_BUY;
request.price = NormalizeDouble(Ask, _Digits);
request.volume = PositionGetDouble(POSITION_VOLUME);
request.deviation = slippage;
request.comment = "Close sell position";
request.arrow_color = clr;
OrderSend(request, result);
}
}
}

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+

この変更されたコードは、MT5で正しくコンパイルできるように、MQL5の構文と関数にアップデートされています。MT5プラットフォームで使用するには、このコードを新しいMQL5ファイルにコピーして貼り付けてください。

GPT-3.5では、どうしてもOrderSend関数をMQL4っぽく使ってしまって、うまくMQL5仕様に対応出来ていないなと感じることが多かったのですが、そのあたりは GPT-4では改善されているようです。その点だけでも既に進化を感じています。

コンパイルエラー箇所の提示

ただし、ChatGPTにもらったコードをそのまま貼り付けてコンパイルしてみたところ、「40 errors, 14 warnings」と複数のエラーが出てしまいました。

エラー内容の列挙

内容はAsk、Bid、requestに関するエラーだったので、以下のように列挙して確認してみます。

以下の複数のエラーが出ました。

‘Ask’ – undeclared identifier
‘Bid’ – undeclared identifier
‘request’ – undeclared identifier
‘request’ – variable expected
‘request’ – cannot convert enum

すみません。以下の修正されたコードをお試しください。

<コードは省略>

上記の修正されたコードをお試しください。このコードは、MQL5言語に変換され、MT5でコンパイルできるはずです。ご不明な点がございましたらお気軽にお問い合わせください。

ここのコードは少し省略しました。内容としては、Ask、Bidを用いていた注文を送信する部分について、trade.Buy()関数やtrade.Sell()関数を使うように変換して提示されました。

Buy() 関数のエラー

しかし、今度はその部分にエラーが出てしまいます。

以下のコードにエラーがあるようです。

trade.Buy(first_lot, _Symbol, ask, slippage, 0, 0, "first_buy", magic_number);

‘Buy’ – wrong parameters count

失礼しました。MQL5では、CTradeクラスの Buy() メソッドのパラメータが異なります。以下のように修正してください。

trade.Buy(first_lot, _Symbol, ask, 0, 0, 0, magic_number, "first_buy");

同様に、 Sell() メソッドのパラメータも修正が必要です。

trade.Sell(first_lot, _Symbol, bid, 0, 0, 0, magic_number, "first_sell");

これらの修正により、エラーが解消されるはずです。ご確認ください。

エラー内容を提示すると、すぐに解決策を示してくれます。

ところが、指定通りに修正してもみても、エラーは解消されませんでした。

こちらの質問が雑すぎたせいで、「’Buy’ – wrong parameters count」がエラー内容だというとこが上手く伝わらなかったのでしょうか。

少しだけ詰めてみます。

‘Buy’ – wrong parameters count というエラーなので、修正内容が異なると思います

申し訳ありません。CTradeクラスのBuy()およびSell()メソッドを利用する場合、以下のようにコードを修正してください。

MqlTradeRequest request;
MqlTradeResult result;

request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.sl = 0;
request.tp = 0;
request.deviation = slippage;
request.magic = magic_number;
request.type_filling = ORDER_FILLING_FOK;

// For Buy orders
request.type = ORDER_TYPE_BUY;
request.volume = first_lot;
request.price = ask;
request.comment = "first_buy";
if(!trade.OrderSend(request, result))
{
    Print("OrderSend failed with error: ", GetLastError());
}

// For Sell orders
request.type = ORDER_TYPE_SELL;
request.volume = first_lot;
request.price = bid;
request.comment = "first_sell";
if(!trade.OrderSend(request, result))
{
    Print("OrderSend failed with error: ", GetLastError());
}

これらの修正により、エラーが解消されるはずです。ご確認ください。

今度は上手く伝わったのか、改めて自主的に改善点を見つけたのかよくわかりませんが、注文送信部分のコードについてrequest形式にまた戻してきました。良さそうな感じに見えます。

コード全体の完成

そこで、改めてコードを書き直してもらいます。

上記を踏まえて、全てのコードを書き直せるでしょうか
上記の修正を踏まえて、全体のコードを以下のように修正しました。
//+------------------------------------------------------------------+
//| nanpin-martin.mq5 |
//| ` Copyright 2022, nanpin-martin.com |
//| "https://nanpin-martin.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, nanpin-martin.com"
#property link "https://nanpin-martin.com/"
#property version "1.00"
#property strict

#include <Trade\Trade.mqh>
CTrade trade;

input double first_lot = 0.01; //初期ロット
input double nanpin_range = 200; //ナンピン幅
input double profit_target = 143; //利益目標
input int magic_number = 10001; //マジックナンバー
double slippage = 10; //スリッページ

//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}

//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
int current_buy_position; //最新のbuyポジション
int current_sell_position; //最新のsellポジション
int buy_position; //buyポジション数
int sell_position; //sellポジション数
double buy_profit; //buyポジションの含み損益
double sell_profit; //sellポジションの含み損益
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

buy_position = 0;
sell_position = 0;
current_buy_position = -1;
current_sell_position = -1;

for(int cnt = 0; cnt < PositionsTotal(); cnt++)
{
ulong ticket = PositionGetTicket(cnt);
if(PositionSelectByTicket(ticket))
{
if(PositionGetInteger(POSITION_MAGIC) != magic_number)
continue;
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
current_buy_position = cnt;
buy_position += 1;
buy_profit += PositionGetDouble(POSITION_PROFIT);
}
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
{
current_sell_position = cnt;
sell_position += 1;
sell_profit += PositionGetDouble(POSITION_PROFIT);
}
}
}

if(buy_position == 0)
{
MqlTradeRequest request;
MqlTradeResult result;

request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.type = ORDER_TYPE_BUY;
request.volume = first_lot;
request.price = ask;
request.sl = 0;
request.tp = 0;
request.deviation = slippage;
request.magic = magic_number;
request.type_filling = ORDER_FILLING_FOK;
request.comment = "first_buy";

if(!trade.OrderSend(request, result))
{
Print("OrderSend failed with error: ", GetLastError());
}
}

if(sell_position == 0)
{
MqlTradeRequest request;
MqlTradeResult result;
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.type = ORDER_TYPE_SELL;
request.volume = first_lot;
request.price = bid;
request.sl = 0;
request.tp = 0;
request.deviation = slippage;
request.magic = magic_number;
request.type_filling = ORDER_FILLING_FOK;
request.comment = "first_sell";

if(!trade.OrderSend(request, result))
{
Print("OrderSend failed with error: ", GetLastError());
}
}

if(buy_position > 0)
{
if(PositionSelectByTicket(PositionGetTicket(current_buy_position)))
{
if(ask < (PositionGetDouble(POSITION_PRICE_OPEN) - nanpin_range * _Point))
{
MqlTradeRequest request;
MqlTradeResult result;
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.type = ORDER_TYPE_BUY;
request.volume = NormalizeDouble(PositionGetDouble(POSITION_VOLUME) * 1.5, 2);
request.price = ask;
request.sl = 0;
request.tp = 0;
request.deviation = slippage;
request.magic = magic_number;
request.type_filling = ORDER_FILLING_FOK;
request.comment = "nanpin_buy";

if(!trade.OrderSend(request, result))
{
Print("OrderSend failed with error: ", GetLastError());
}
}
}
}

if(sell_position > 0)
{
if(PositionSelectByTicket(PositionGetTicket(current_sell_position)))
{
if(bid > (PositionGetDouble(POSITION_PRICE_OPEN) + nanpin_range * _Point))
{
MqlTradeRequest request;
MqlTradeResult result;
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.type = ORDER_TYPE_SELL;
request.volume = NormalizeDouble(PositionGetDouble(POSITION_VOLUME) * 1.5, 2);
request.price = bid;
request.sl = 0;
request.tp = 0;
request.deviation = slippage;
request.magic = magic_number;
request.type_filling = ORDER_FILLING_FOK;
request.comment = "nanpin_sell";

if(!trade.OrderSend(request, result))
{
Print("OrderSend failed with error: ", GetLastError());
}
}
}
}

if(buy_position > 0 && buy_profit > profit_target * buy_position)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && PositionGetInteger(POSITION_MAGIC) == magic_number)
{
trade.PositionClose(ticket, slippage);
}
}
}
}

if(sell_position > 0 && sell_profit > profit_target * sell_position)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && PositionGetInteger(POSITION_MAGIC) == magic_number)
{
trade.PositionClose(ticket, slippage);
}
}
}
}
}
//+------------------------------------------------------------------+

今度は良い感じに仕上がったようです。コンパイルしてみたらエラーはありませんでした。

GPT-3.5の時は、エラーについて何回聞き直しても結局ChatGPTの実力だけではエラーを解消することが出来ませんでしたので、自己解決力はかなり向上しています。このあたりもGPT-4の進化を感じます。

作成したEAでバックテストを行ってみる

さて、無事コンパイルが完了しましたので、作成したMT5用EAでバックテストを行ってみます。

XMで注文が入るように微修正

バックテストはXMTradingのGOLDで行ってみました。すると、注文が全く入りません。
ただし、この点は大体予想が出来ていたので、少し誘導的に以下のように聞いてみます。
バックテストを行ったら、以下のエラーが出ました。
OrderSend failed with error: 4756
おそらく、ORDER_FILLING_FOKのせいだと思います。
OrderSendでエラー4756が発生した場合、注文のタイプが許可されていないことを意味します。ORDER_FILLING_FOKをORDER_FILLING_IOCに変更してみてください。修正後のコードは以下のようになります。
   if (buy_position == 0)
   {
      MqlTradeRequest request;
      MqlTradeResult result;

      request.action = TRADE_ACTION_DEAL;
      request.symbol = _Symbol;
      request.type = ORDER_TYPE_BUY;
      request.volume = first_lot;
      request.price = ask;
      request.sl = 0;
      request.tp = 0;
      request.deviation = slippage;
      request.magic = magic_number;
      request.type_filling = ORDER_FILLING_IOC;
      request.comment = "first_buy";

      if (!trade.OrderSend(request, result))
      {
         Print("OrderSend failed with error: ", GetLastError());
      }
   }

   if (sell_position == 0)
   {
      MqlTradeRequest request;
      MqlTradeResult result;

      request.action = TRADE_ACTION_DEAL;
      request.symbol = _Symbol;
      request.type = ORDER_TYPE_SELL;
      request.volume = first_lot;
      request.price = bid;
      request.sl = 0;
      request.tp = 0;
      request.deviation = slippage;
      request.magic = magic_number;
      request.type_filling = ORDER_FILLING_IOC;
      request.comment = "first_sell";

      if (!trade.OrderSend(request, result))
      {
         Print("OrderSend failed with error: ", GetLastError());
      }
   }

これで、エラー4756が解決されることが期待されます。もし、問題が解決しない場合は、サーバーの許可されている注文タイプを確認する必要があります。その場合、SymbolInfoInteger()関数を使用してSYMBOL_FILLING_MODEを調べることができます。

もし他に質問や懸念があればお気軽にお問い合わせください。

ChatGPTに回答いただいた通り、XMTradingの場合はORDER_FILLING_IOCでないと注文が入りませんね。
これは、どこのFX業者の口座を使用するとか条件を伝えなかったので、難しい部分かなと思います。
ただし、サーバーの許可されている注文タイプを確認する方法まで教えてくれているので、ChatGPTに質問を続ければ解決出来そうな感触ではあります。

XM向けのMT5用EAの完成

ちなみに、ORDER_FILLING_FOKは全コードで4ヶ所あります。それを全てORDER_FILLING_IOCに変えてください。全コードをコピペして、4ヶ所修正してコンパイルするだけで、XMTrading向けのMT5用ナンピンマーチンEAの完成です。

バックテスト結果も良好

コンパイルされたファイルをそのまま使ったデフォルト設定におけるバックテストです。

取引対象はXMTradingのStandard口座のGOLDで、バックテスト期間は2022/11/1〜2023/1/31の3ヶ月間です。

勝率は96%超、プロフィットファクターは6.43と、ナンピンマーチンEAらしい右肩上がりのグラフにしっかりなっています。ある程度想定通りなので、ロジックも問題なく実装出来ていそうなことがわかります。

まとめ

これまでこのサイトで見てきたChatGPT関連の記事はGPT-3.5によるものが多かったですが、MQL4であればそれなりに完成度の高いものが作成出来るが、MQL5だとかなりイマイチという印象が大きかったです。

ただし、今回のGPT-4に関してはその印象がだいぶ変わりました。一発で完璧なコードというわけにはいきませんでしたが、エラーや問題点を伝えてあげるだけで自力で解決出来そうな感触は十分あり、プログラミング初心者でも上手く指示してあげればMT5用EAを作成することも出来る可能性は高いです。

また、「MQL4のコードをMQL5に変換してくれる夢のようなツール」という点では、かなり近いものに仕上がってきているように思います。

GPT-3.5とGPT-4の違い

最後に、こんな質問をしてみました。

MQL5のコーディング能力について、GPT-3.5とGPT-4の違いを教えてください。

私はOpenAIのGPT-4ベースのAIであり、GPT-3.5と比較して、より広範囲の知識と文脈理解能力が向上しています。しかし、MQL5のコーディング能力に関しては、GPT-4とGPT-3.5の間で大きな違いはありません。どちらもMQL5の基本的なコードの生成と解析が可能ですが、高度なコーディングや最適化に関しては、専門的な知識と経験が必要になる場合があります。

どちらのモデルもプログラミング言語のサポートがありますが、コーディングの複雑さや特定の問題に対処する能力は、専門的なプログラマーや開発者と比べて限定的です。MQL5のコーディングの問題に対処する際には、GPT-4もGPT-3.5も、適切な知識を持っていることを前提として助けを提供しますが、専門家の助言を求めることも検討してください。

ありがとうございます。それでも、GPT-4の方がコーディング能力が上がっているように感じました。進化のポイントはどこにありますか。

GPT-4は、GPT-3.5と比較して、さらに大規模なデータセットで訓練されており、より幅広い知識と文脈理解能力を持っています。これにより、一般的にはGPT-4がGPT-3.5よりも優れたコーディング能力を持っていると感じられることがあります。進化のポイントは以下の通りです。

  1. 大規模なデータセット: GPT-4は、より多くの情報と知識を持つため、コーディングの問題に対してより適切な解決策を提案できることがあります。
  2. 文脈理解力: GPT-4は、文脈をより正確に理解し、適切な回答や提案を行う能力が向上しています。これにより、ユーザーの質問に対してより適切なコードの生成や解析が可能になります。
  3. 一貫性と精度: GPT-4は、より一貫性のある回答や提案を行う能力が向上しており、特に長い会話や複雑な問題に対処する際に有益です。

しかし、GPT-4も完璧ではありませんし、プログラミング言語のサポートに関しては依然として限定的です。特に、特定のプログラミング言語やフレームワークに関する最新の情報や高度な知識については、専門家や開発者に相談することをお勧めします。

この回答を見るだけでも、ChatGPTの説明能力は少し向上しているように感じます。
MQL5は比較的新しいので、GPT-3.5では手が届かなかった部分まで、GPT-4では学習することが出来てスキルが向上したということなのでしょうね。

他にも試してみたら、またご報告します。

ChatGPT(GPT-3.5)関連記事

GPT-3.5の時に色々試してみた記事はこちらです。

キャッシュバック口座の開設

作成したEAを利用して実際に運用する際は、通常の口座開設ではなく、キャッシュバック口座を開設するのがおすすめです。以下の記事で、キャッシュバックサイト経由で海外FX口座を開設する際のメリットとデメリットをまとめていますのでご覧ください。

利用者の特性に応じて、リアル口座をどのように開設するのが最適かを考える参考になると思います。

タイトルとURLをコピーしました