最近話題のChatGPTでFXトレーディングEAを作成してみた
最近話題のAI技術、ChatGPTを利用して、FXトレーディングのためのEA(自動売買システム)を作成してみました。ここでは、その過程と得られた結果について共有します。
一定期間の最高値・最安値ライン越えでエントリーするEAを作成
今回作成してもらったEAは、こちらの記事「[EA作成]直近一定期間の最高値・最安値ライン越えでエントリー」で作成した、一定期間の最高値・最安値ライン越えでエントリーするEAです。
ChatGPTへの指示方法
ChatGPTに依頼をするのに、どのような依頼の仕方をするのがよいのかわからなかったので、ChatGPT自身に聞いてみたところ、以下の内容を指定して欲しいと言われました。
具体的な目的や要件の明記:
EAやインジケータの目的や機能について具体的に説明してください。例えば、特定のテクニカル指標に基づくトレード戦略、または市場データの分析方法など。
使用する指標や条件の詳細:使用するテクニカル指標(例:移動平均、RSI、MACD)や、それらの特定の設定値(期間、レベルなど)。
トレード条件やルール(例:特定の指標のクロスオーバー時にエントリー、特定の時間帯でのトレード制限)。
リスク管理のパラメータ:ストップロスやテイクプロフィットの設定、ロットサイズの計算方法など。
プラットフォームとプログラミング言語の指定:MetaTrader 4(MT4)または MetaTrader 5(MT5)のどちらで使用するか、そしてMQL4またはMQL5のどちらの言語でコードを書くかを明記してください。
パフォーマンスや効率性に関する要望:実行速度、メモリ使用量、処理効率などの技術的な要望があれば、それも含めてください。
その他の特別な要件:グラフィカルな表示、アラートの設定、ログの記録方法など、特別な機能が必要な場合は、それについても説明してください。
そこで、その形式に従い、まずは以下の内容で依頼してみました。
以下の条件でEAの作成をお願いします。
EAタイトル:最高値、最安値越えでトレードするEA
1.このEAの目的や要件
直近の最高値、最安値越えでポジションエントリー、一定値以上の利益達成または一定値以上の損益発生でポジションをクローズするEA2.使用する指標や条件の詳細:
①使用するパラメータ
extern int MagicNumberB = 00000001;
extern int MagicNumberS = 00000002;
extern int Slippage = 3;
extern int スプレッド上限 = 5;
extern double ロット = 0.1;
extern int 最高値、最安値の判定期間の開始位置 = 2;
extern int 最高値、最安値の判定期間 = 20;
extern double ストップロス(pips) = 20;
extern double テイクプロフィット(pips) = 20;
int timeframe = PERIOD_M15; // timeframe②直近の最高値、最安値の判定
timeframeで指定した足での一定期間(最高値、最安値の判定期間の開始位置、期間はパラメータで指定)内の最高値、最安値を最高値、最安値とする③エントリー条件
最高値より高い価格で、timeframeで指定した足が確定タイミングで買いポジションをエントリーする
最安値より安い価格で、timeframeで指定した足が確定タイミングで買いポジションをエントリーする3.リスク管理のパラメータ:
ストップロスやテイクプロフィット、ロットサイズはパラメータで指定するロットサイズ=ロット
ストップロス=エントリー価格より指定pips分の損益位置
テイクプロフィット=エントリー価格より指定pips分の利益位置4.プラットフォームとプログラミング言語の指定:
MetaTrader 4(MT4)
MQL45.パフォーマンスや効率性に関する要望:
チック間隔ではなく、1秒経過毎にエントリー条件またはクローズ条件を判定する
前回実行時から1秒経過していない場合は条件判定をしない
1秒はパラメータで変更できるようにする6.その他の特別な要件:
エントリー条件またはクローズ条件を満たしたときに、エントリー価格とストップロス、テイクプロフィットの価格
および、エントリーした条件をログで残す
生成されたコード
この依頼をもとに生成されたコードは以下です。
思ったより、なかなか完成度高いコードじゃないでしょうか。
//+------------------------------------------------------------------+
//| Breakout EA |
//| |
//| EAの目的: 直近の最高値、最安値を越えた場合にエントリーし、 |
//| 一定の利益または損失でポジションをクローズする。 |
//+------------------------------------------------------------------+
#include <stderror.mqh>
#include <stdlib.mqh>
// パラメータの設定
extern int MagicNumberB = 00000001;
extern int MagicNumberS = 00000002;
extern int Slippage = 3;
extern int MaxSpread = 5;
extern double Lot = 0.1;
extern int StartPeriod = 2;
extern int Period = 20;
extern double StopLossPips = 20;
extern double TakeProfitPips = 20;
extern int Timeframe = PERIOD_M15;
extern int CheckInterval = 1; // エントリーまたはクローズ条件をチェックする間隔(秒)
double HighestPrice, LowestPrice;
datetime LastCheckTime;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// 最初のチェック時間を設定
LastCheckTime = TimeCurrent() - CheckInterval;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1秒ごとにチェック
if(TimeCurrent() - LastCheckTime < CheckInterval) return;
LastCheckTime = TimeCurrent();
// 最高値、最安値の計算
HighestPrice = High[iHighest(NULL, Timeframe, MODE_HIGH, Period, StartPeriod)];
LowestPrice = Low[iLowest(NULL, Timeframe, MODE_LOW, Period, StartPeriod)];
// エントリー条件のチェック
CheckEntryConditions();
// ポジション管理
ManagePositions();
}
//+------------------------------------------------------------------+
//| エントリー条件のチェック |
//+------------------------------------------------------------------+
void CheckEntryConditions()
{
double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);
double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);
// 買いエントリー条件
if(Ask > HighestPrice && !IsOrderOpen(MagicNumberB))
{
double sl = Ask - StopLossPips * _Point;
double tp = Ask + TakeProfitPips * _Point;
if(OrderSend(_Symbol, OP_BUY, Lot, Ask, Slippage, sl, tp, "Breakout Buy", MagicNumberB, 0, clrBlue) > 0)
{
// ログ記録
Print("Buy Order Opened: Price = ", Ask, ", SL = ", sl, ", TP = ", tp);
}
}
// 売りエントリー条件
if(Bid < LowestPrice && !IsOrderOpen(MagicNumberS))
{
double sl = Bid + StopLossPips * _Point;
double tp = Bid - TakeProfitPips * _Point;
if(OrderSend(_Symbol, OP_SELL, Lot, Bid, Slippage, sl, tp, "Breakout Sell", MagicNumberS, 0, clrRed) > 0)
{
// ログ記録
Print("Sell Order Opened: Price = ", Bid, ", SL = ", sl, ", TP = ", tp);
}
}
}
//+------------------------------------------------------------------+
//| ポジション管理関数 |
//+------------------------------------------------------------------+
void ManagePositions()
{
// ポジションの管理コードをここに記述
}
//+------------------------------------------------------------------+
//| 特定のマジックナンバーを持つオーダーがオープンしているかをチェック |
//+------------------------------------------------------------------+
bool IsOrderOpen(int magicNumber)
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS) && OrderMagicNumber() == magicNumber)
return true;
}
return false;
}
//+------------------------------------------------------------------+
とはいえ、実際にコンパイル、バックテストみると問題はいくつかあり、以下のような内容を徐々に修正してもらいました。
・以下は不要(Ask,Bidがシステムと重複定義されている)
double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);
double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);
・double sl, tpは2重定義になるので、if文の外で定義
・エントリー条件の判定は、足確定で判定したいので、クローズ値で判定する
Close[1]だと、チャートの時間設定に依存してしまうので、iClose()を使う
・ManagePositions()はなしでよい
・買いエントリーは、ASK値で、売りエントリーは、BID値で行う
で、最終的に生成されたコードは以下です。
//+------------------------------------------------------------------+
//| Breakout EA |
//| |
//| 直近の最高値、最安値を越えた場合にエントリーし、一定の利益または損失で |
//| ポジションをクローズする。 |
//+------------------------------------------------------------------+
#include <stderror.mqh>
#include <stdlib.mqh>
// パラメータの設定
extern int MagicNumberB = 00000001;
extern int MagicNumberS = 00000002;
extern int Slippage = 3;
extern int MaxSpread = 5;
extern double Lot = 0.1;
extern int StartPeriod = 2;
extern int Period = 20;
extern double StopLossPips = 20;
extern double TakeProfitPips = 20;
extern int Timeframe = PERIOD_M15;
extern int CheckInterval = 1; // エントリーまたはクローズ条件をチェックする間隔(秒)
double HighestPrice, LowestPrice;
datetime LastCheckTime;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
LastCheckTime = TimeCurrent() - CheckInterval;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(TimeCurrent() - LastCheckTime < CheckInterval) return;
LastCheckTime = TimeCurrent();
HighestPrice = High[iHighest(NULL, Timeframe, MODE_HIGH, Period, StartPeriod)];
LowestPrice = Low[iLowest(NULL, Timeframe, MODE_LOW, Period, StartPeriod)];
CheckEntryConditions();
}
//+------------------------------------------------------------------+
//| エントリー条件のチェック |
//+------------------------------------------------------------------+
void CheckEntryConditions()
{
double ClosePrice = iClose(NULL, Timeframe, 1); // 指定した時間枠での前の足のクローズ値
double sl, tp; // ストップロスとテイクプロフィット
// 買いエントリー条件
if(ClosePrice > HighestPrice && !IsOrderOpen(MagicNumberB))
{
double askPrice = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);
sl = askPrice - StopLossPips * _Point;
tp = askPrice + TakeProfitPips * _Point;
if(OrderSend(_Symbol, OP_BUY, Lot, askPrice, Slippage, sl, tp, "Breakout Buy", MagicNumberB, 0, clrBlue) > 0)
{
Print("Buy Order Opened: Price = ", askPrice, ", SL = ", sl, ", TP = ", tp);
}
}
// 売りエントリー条件
if(ClosePrice < LowestPrice && !IsOrderOpen(MagicNumberS))
{
double bidPrice = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);
sl = bidPrice + StopLossPips * _Point;
tp = bidPrice - TakeProfitPips * _Point;
if(OrderSend(_Symbol, OP_SELL, Lot, bidPrice, Slippage, sl, tp, "Breakout Sell", MagicNumberS, 0, clrRed) > 0)
{
Print("Sell Order Opened: Price = ", bidPrice, ", SL = ", sl, ", TP = ", tp);
}
}
}
//+------------------------------------------------------------------+
//| 特定のマジックナンバーを持つオーダーがオープンしているかをチェック |
//+------------------------------------------------------------------+
bool IsOrderOpen(int magicNumber)
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS) && OrderMagicNumber() == magicNumber)
return true;
}
return false;
}
//+------------------------------------------------------------------+
実行できるコードができあがりました!
EAのバックテスト実行結果
パラメータ調整等して、バックテストしてみた結果は以下です。
ちゃんと意図通り動いてくれてましたが、結果自体はあんまりですね。
まあ、単純ロジックなので、これは仕方ないですね。
※Exnessという海外口座を使った金/米ドルでのバックテスト結果です
結論
ChatGPTを用いたEA作成は、指示方法などの確立できれば、初心者から中級者、上級者にとっても非常に有益な方法になりそうです。
今後もこのツールを活用して、EA作成の効率化、自動化の可能性を模索していきたいと思います。
P.S. 何か有益な情報あれば、共有頂けたら幸いです。
コメント