日夜「楽にEAを作れないか?」と考えている管理人はChatGPTで楽にEAを作るにはどうすればいいのか、最近考えています。
今日はゴトー日仲値アノマリーEAを作ってみます。市販ソフトなら2万円相当です。
以下の条件でMQL4を使ってEAを作成してください。
日本時間0時にロング
日本時間9時55分に決済
以下は、指定された条件に基づいて、MQL4でEAを作成するためのサンプルコードです。このコードは、日本時間で毎日0時にロングポジションを開き、日本時間で毎日9時55分に決済する単純なEAです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
// EAのプロパティ extern double Lots = 0.1; // 取引量 extern int StopLoss = 100; // ストップロス extern int TakeProfit = 200; // テイクプロフィット // グローバル変数 bool IsPositionOpen = false; // ポジションが開かれているかどうか // エントリー関数 void OpenPosition() { // ロングポジションを開く OrderSend(Symbol(), OP_BUY, Lots, Ask, 5, Bid - StopLoss * Point, Bid + TakeProfit * Point, "Long", 0, 0, Green); // ポジションが開かれたことを記録する IsPositionOpen = true; } // イグジット関数 void ClosePosition() { // ポジションを決済する OrderClose(OrderTicket(), OrderLots(), Bid, 5, Red); // ポジションが閉じられたことを記録する IsPositionOpen = false; } // オンシグナル関数 void OnTick() { // 現在の時刻を取得する datetime currentTime = TimeLocal(); // 0時になったらロングポジションを開く if (!IsPositionOpen && TimeHour(currentTime) == 0 && TimeMinute(currentTime) == 0) { OpenPosition(); } // 9時55分になったらポジションを決済する if (IsPositionOpen && TimeHour(currentTime) == 9 && TimeMinute(currentTime) == 55) { ClosePosition(); } } |
このEAは、指定された条件に基づいて、毎日自動的に取引を行います。取引量、ストップロス、テイクプロフィットなどのパラメータは、EAのプロパティとして設定できます。ただし、このEAは単純なものであり、市場の状況によっては効果的でない場合があります。したがって、実際に使用する前に、バックテストやデモトレードで検証することをお勧めします。
うーん、惜しい!!
間違ってはないけど、足りてない部分もあるのでこのままではまともに使えないのでもうちょっとプロンプトを変更してみます。
・・・
試行錯誤してみたけど、残念ながら満足のいくコードは生成できませんでした。
Table of Contents
現在のChatGPTのEA作成の懸念点
- MT4の仕様についての理解が乏しい
- 一個出来たら一個足りない部分がでてくる
- MT4の古いコードと最新のコードがごっちゃになってて古いコード(start関数等)を使っている
- MT4の仕様をよくわかってないので、現在のポジション情報を取得する方法がわからない
- MT4の仕様をよくわかってないので、MT4のサーバータイムを日本時間へ変換できない
- MT4とMT5がごっちゃになっている
このためChatGPTを使う人間がMT4の仕様について詳しくないと、間違った情報をそのまま信用して使ってしまう恐れがあるので注意です。
本気でプロンプトを書いて注文してみた
以下の条件でMQL4を使ってMT4のEAを作成してください。
- MagicNumberは510
- 5の倍数日または次の土曜日日曜日が5の倍数日の場合かつ、ポジション数が0でかつ、日本時間0時0分~日本時間9時55分ならロング
- 日本時間9時55分を過ぎていてポジション保有なら決済
- ストップリミットは設定しない
- アメリカのサマータイムは3月第2日曜日から11月の第1日曜日まで
以下の手順でプログラムを組み立ててください。
- サマータイムなら真を返す関数「bool is_summer()」を作る
- サマータイムなら現在の時刻に6時間を足して返却、冬時間なら7時間を足して返却する「datetime get_japan_time()」を作る
- void position_entry(int side) をつくる
- void position_close(int side) をつくる
- int position_count(int side) をつくる
- position_count(0)が0の時、ロングする
- position_count(0)が0ではない時、ロングを決済する
注意点として
- OnTick()内部で各関数を呼び出すこと
- position_countはMagicNumberを含めること
- is_summer()で計算する時刻はTimeCurrent()を使うこと
- 説明コメントは不要です
- japantime は夏ならTimeCurrent() + 6 * 60 * 60です
サマータイムは以下のコードを参考にしてください
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
bool is_summer() { datetime now = TimeCurrent(); int year = TimeYear(now); int month = TimeMonth(now); int day = TimeDay(now); int dayOfWeek = TimeDayOfWeek(now); int hours = TimeHour(now); if (month < 3 || month > 11) { return false; } if (month > 3 && month < 11) { return true; } // アメリカのサマータイムは3月の第2日曜日から11月の第1日曜日まで if (month == 3) { int dstStart = 14 - dayOfWeek; if (day >= dstStart) { return true; } else { return false; } } if (month == 11) { int dstEnd = 7 - dayOfWeek; if (day < dstEnd) { return true; } else { return false; } } return false; } |
本気でプロンプトを書いた結果w
以下が要求事項に基づいてプログラムを組み立てたものです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
// サマータイムなら真を返す関数 bool is_summer() { datetime now = TimeCurrent(); int year = TimeYear(now); int month = TimeMonth(now); int day = TimeDay(now); int dayOfWeek = TimeDayOfWeek(now); int hours = TimeHour(now); if (month < 3 || month > 11) { return false; } if (month > 3 && month < 11) { return true; } // アメリカのサマータイムは3月の第2日曜日から11月の第1日曜日まで if (month == 3) { int dstStart = 14 - dayOfWeek; if (day >= dstStart) { return true; } else { return false; } } if (month == 11) { int dstEnd = 7 - dayOfWeek; if (day < dstEnd) { return true; } else { return false; } } return false; } // サマータイムに合わせた日本時間を返す関数 datetime get_japan_time() { if (is_summer()) { return TimeCurrent() + 6 * 60 * 60; } else { return TimeCurrent() + 7 * 60 * 60; } } // ポジション数を返す関数 int position_count(int side) { int count = 0; for (int i = 0; i < OrdersTotal(); i++) { if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if (OrderMagicNumber() == 510 && OrderSymbol() == Symbol() && OrderType() == side) { count++; } } } return count; } // ポジションを新規に取る関数 void position_entry(int side) { if (position_count(0) == 0 && (TimeDay(get_japan_time()) % 5 == 0 || TimeDayOfWeek(get_japan_time()) >= 5)) { if (TimeHour(get_japan_time()) < 10) { OrderSend(Symbol(), side, 0.1, Bid, 1, 0, 0, "EA", 510, 0, CLR_NONE); } } } // ポジションを決済する関数 void position_close(int side) { if (position_count(0) > 0 && TimeHour(get_japan_time()) >= 10) { for (int i = 0; i < OrdersTotal(); i++) { if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if (OrderMagicNumber() == 510 && OrderSymbol() == Symbol() && OrderType() == side) { OrderClose(OrderTicket(), OrderLots(), Bid, 1, CLR_NONE); } } } } } void OnTick() { position_entry(OP_BUY); position_close(OP_BUY); } |
めちゃくちゃ惜しいw
エントリーしたらエントリーをストップする条件があれば問題なさそうです。
Ontickとposition_entryをちょっと修正します。
1 2 3 4 5 6 7 8 9 |
bool entry_on = true; void OnTick() { static datetime prev_date=0; if(prev_date!=iTime(NULL,1440,0)){prev_date=iTime(NULL,1440,0);entry_on = true;} position_entry(0); position_close(0); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
void position_entry(int side) { if(!entry_on){return;} int count = position_count(side); if (count == 0) { datetime japan_time = get_japan_time(); int hour = TimeHour(japan_time); int minute = TimeMinute(japan_time); int day = TimeDay(japan_time); int weekday = TimeDayOfWeek(japan_time); if ((weekday % 5 == 0 && day % 5 == 0) || (weekday == 6 && day % 5 == 1) || (weekday == 0 && day % 5 == 2)) { if (hour >= 0 && minute >= 0) { OrderSend(Symbol(), OP_BUY, 0.01, Ask, 0, 0, 0, "", magicNumber, 0, Green); entry_on = false; } } } } |
サンプルコード全文
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
int magicNumber = 510; bool is_summer() { datetime now = TimeCurrent(); int year = TimeYear(now); int month = TimeMonth(now); int day = TimeDay(now); int weekday = TimeDayOfWeek(now); if (month < 3 || month > 11) return false; if (month > 3 && month < 11) return true; int previousSunday = day - weekday; if (month == 3) { return previousSunday >= 8; } else { return previousSunday <= 0; } } datetime get_japan_time() { datetime now = TimeCurrent(); if (is_summer()) { return (now+6*3600); } else { return (now+7*3600); } } void position_entry(int side) { if(!entry_on){return;} int count = position_count(side); if (count == 0) { datetime japan_time = get_japan_time(); int hour = TimeHour(japan_time); int minute = TimeMinute(japan_time); int day = TimeDay(japan_time); int weekday = TimeDayOfWeek(japan_time); if ((weekday % 5 == 0 && day % 5 == 0) || (weekday == 6 && day % 5 == 1) || (weekday == 0 && day % 5 == 2)) { if (hour >= 0 && minute >= 0) { OrderSend(Symbol(), OP_BUY, 0.01, Ask, 0, 0, 0, "", magicNumber, 0, Green); entry_on = false; } } } } void position_close(int side) { int count = position_count(side); if (count > 0) { datetime japan_time = get_japan_time(); int hour = TimeHour(japan_time); int minute = TimeMinute(japan_time); if (hour >= 9 && minute >= 55) { for (int i = OrdersTotal() - 1; i >= 0; i--) { if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){ if(OrderMagicNumber() == magicNumber && OrderSymbol() == Symbol() && OrderType() == OP_BUY) { OrderClose(OrderTicket(), OrderLots(), Bid, 0, Red); } } } } } } int position_count(int side) { int count = 0; for (int i = OrdersTotal() - 1; i >= 0; i--) { if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){ if(OrderMagicNumber() == magicNumber && OrderSymbol() == Symbol() && OrderType() == OP_BUY) { count++; } } } Print(count); return count; } bool entry_on = true; void OnTick() { static datetime prev_date=0; if(prev_date!=iTime(NULL,1440,0)){prev_date=iTime(NULL,1440,0);entry_on = true;} position_entry(0); position_close(0); } |
サンプルコードのバックテスト結果
おわり
少しは手ごたえを感じましたが、プロンプトを考えるのに3時間ぐらいかかりましたw
これなら1から作ったほうが速い気もしますが、億劫だけど興味ある分野のファーストステップとして活用するといいと思います。
プロンプトの作成になれてきたらもっと早く完成させることが出来そうです。
BybitがGoogleのIPアドレス規制をしているためです。国内のVPSなら使…
自分のbotで使ってるAPIキーを使用しているんですが、 You have br…
pybit 最新版にコードを変更しました。コードとrequirements.tx…
お返事ありがとうございます。はい。pybit==2.3.0になっております。
コードはあっていると思います。rewuirements.txtは「pybit==…