ChatGPTで作るMT4/MT5サインツール入門|作り方と注意点をやさしく解説(MQL4/MQL5)

サインツールの作り方 無料インジケーター

AIを使えば、プログラミングの知識がほとんどなくてもサインツールを作れる時代になりました。

特にChatGPTやGeminiを使えば、作りたい内容をそのまま文章で伝えるだけで、MQL5のコードを自動で生成してくれます。

ただし、実際に使えるレベルのツールを作るには「正しい依頼の仕方」や「よくある落とし穴」を理解しておくことが重要です。

何も知らないまま進めると、エラーやバグにハマってしまい、逆に遠回りになることも少なくありません。

この記事では、AIを使ったサインツールの作り方を、実際のコード例を交えながら初心者向けに分かりやすく解説していきます。

ChatGPTやGeminiを使ったサインツールの作り方

チャットGPTにサインツールの作成を依頼2

ChatGPTやGeminiを使ったサインツールの作り方は、作って欲しい内容をChatGPTやGeminiにそのまま伝えるだけです。

例えば陽線が3回連続で続いた時にサインが出てアラートが鳴るサインツールの場合

ChatGPTやGeminiに「MQL5で陽線が3回連続で続いた時にサイン出てアラートが鳴るインジケーターを作って」と依頼します。

この時重要なのが「MQL5」と「インジケーター」です。

この2つをしっかり伝えないとMQL4で作ったり、EAで作ったりします。

「陽線が3本でサイン&アラート」のサインツールのコードを紹介

「陽線が3本続いたタイミング」でサインを表示

以下は実際にChatGPTが作ったコードになります。


//+------------------------------------------------------------------+
//| 3連続陽線でサインを出すバージョン      |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1

#property indicator_label1 "Buy Signal"
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

double BuySignalBuffer[];
datetime LastAlertBarTime = 0;

int OnInit()
{
    SetIndexBuffer(0, BuySignalBuffer, INDICATOR_DATA);
    PlotIndexSetInteger(0, PLOT_ARROW, 233);
    return (INIT_SUCCEEDED);
}

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[])
{
    if (rates_total < 4) // 3連続陽線なので最低4本必要
        return 0;

    int start = MathMax(prev_calculated - 1, 3);

    if (prev_calculated == 0)
    {
        ArrayInitialize(BuySignalBuffer, EMPTY_VALUE);
    }

    for (int i = start; i <= rates_total - 2; i++)
    {
        bool isBullish1 = (close[i] > open[i]);        // 3本目(今確定したバー)
        bool isBullish2 = (close[i - 1] > open[i - 1]); // 2本目
        bool isBullish3 = (close[i - 2] > open[i - 2]); // 1本目
        bool isBullish4 = (close[i - 3] > open[i - 3]); // 4本目(4連続チェック用)

        // ★「ちょうど3連続の時のみ」サインを出す → 4本目が陽線ならスルー
        if (isBullish1 && isBullish2 && isBullish3 && !isBullish4)
        {
            BuySignalBuffer[i] = low[i] - (Point() * 10);

            if (i == rates_total - 2 && LastAlertBarTime != time[i])
            {
                string msg = StringFormat("【アラート】3連続陽線!確定足: %s", TimeToString(time[i], TIME_DATE | TIME_MINUTES));
                Alert(msg);
                PlaySound("alert.wav");

                LastAlertBarTime = time[i];
            }
        }
        else
        {
            BuySignalBuffer[i] = EMPTY_VALUE;
        }
    }

    return rates_total;
}

MetaTraderにサインツールのコードを貼り付け動かしてみよう

実際にサインツールを
動かしてみよう

MT5のMetaTraderを使って実際にサインを表示させるまでの流れを紹介します。

※MT4も同じ流れになります。

MT5でサインコードを起動する設定1

まずはMT5を起動させ「ツール」より「MetaQuotes 言語エディタ」を選択します。

MT5でサインコードを起動する設定2

MetaTraderが開きます。

MetaTraderの「ファイル」より「新しいファイル」を選択します。

MT5でサインコードを起動する設定3

「MQLウィザード:ファイル」が表示されるので「カスタムインディケータ」を選択して「次へ」ボタンをクリックします。

MT5でサインコードを起動する設定4

ファイル名(名前)を入力します。

デフォルトでは「Indicators¥」と表示されています。ファイルの位置になりますので、「Indicators¥」はそのままで、「Indicators¥ファイル名」とします。

今回はyousen3にしています。

名前を入力後「次へ」ボタンをクリックします。

MT5でサインコードを起動する設定5

次に表示される画面はそのまま「次へ」をクリックします。

MT5でサインコードを起動する設定6

次に表示される画面はそのまま「完了」ボタンをクリックします。

MT5でサインコードを起動する設定7

デフォルトのテンプレートが表示されます。

MT5でサインコードを起動する設定8

デフォルトのテンプレートの中身を消します。

MT5でサインコードを起動する設定9

3連続陽線でサインを出すコードをコピーして貼り付けます。

MT5でサインコードを起動する設定10

画面上部にある「コンパイル」ボタンをクリックします。

MT5でサインコードを起動する設定11

ツールボックス内でエラーが表示されない事を確認します。

MT5でサインコードを起動する設定12

※MT5を起動します。先ほどMetaTraderで保存したファイルはMT5に反映されています。

MT5のナビゲーターの「指標」の中に「yousen3」がある事を確認します。

「yousen3」をダブルクリックします。

MT5でサインコードを起動する設定13

ポップアップが表示されるので「OK」ボタンをクリックします。

MT5でサインコードを起動する設定14

3連続で陽線の場合サインが出ている事を確認します。

MT5でサインコードを起動する設定15

コードの修正に関しては「yousen3」を右クリックして「変更」を選ぶと、MetaTraderが起動して修正する事が出来ます。

サインツールのコードを徹底解説

コードを
1から10まで徹底解説

ChatGPTやGeminiだけでもサインツールを作ることは可能ですが、知識を増やした方が後々楽にサインツールを作れるようになります。

まずはシンプルなコードから覚えましょう。

変数や関数、条件式など完全解説していますので、分からない箇所の解説をご確認下さい。

#propertyを解説


#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1

#property indicator_label1 "Buy Signal"
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

#propertyは、インジケーターを作るときに、「どこに表示するか」や「色」・「線の形」などを簡単に決める事が出来ます。

#propertyの内容
#property 設定 説明
indicator_chart_window チャートのメイン画面にインジケーターを表示する
indicator_buffers 1 データを入れる箱を1つ使う
indicator_plots 1 チャートに表示するサインやラインは1つ
indicator_label1 "Buy Signal" サインの名前を「Buy Signal」にする
indicator_type1 DRAW_ARROW 矢印を表示する
indicator_color1 clrGreen 矢印の色を緑にする
indicator_style1 STYLE_SOLID 線のスタイルは「実線」にする
indicator_width1 2 矢印や線の太さ(大きさ)を「2」にする
indicator_buffers 1(バッファ)を解説
【重要】
バッファを理解しよう

indicator_buffers 1

indicator_buffers 1 は、「バッファを1つ用意する」という意味になります。

※indicator_buffers 2にするとバッファを2つ用意します。

バッファとは、サインやラインなどを表示するための「データを入れる箱」のようなものです。

MetaTraderはこのバッファを常に監視していて、値が入ると自動的にその位置にサインを表示してくれます。

今回のサインツールでは、チャートに表示するサインが1つだけなので、バッファも1つで十分です。もし、ほかのサインを追加で表示したい場合は、そのサイン用にもう1つバッファを用意する必要があります。

indicator_plots1を解説
MQL5から登場した
indicator_plotsを解説

indicator_plots は、インジケーターがチャートに表示する線や矢印など、「描画する項目の数」を指定する設定です。

MQL5から登場した「宣言」になります。

MQL4では、チャートに線や矢印を表示するとき、「何を何個表示するのか」を最初に決める必要は無く、線の種類や色などをバラバラに設定していました。

MQL4の場合
描画のタイプを設定(SetIndexStyle)、矢印の種類を設定(SetIndexArrow)、バッファの登録(SetIndexBuffer)

SetIndexStyle(0, DRAW_ARROW, STYLE_SOLID, 2, clrGreen);
SetIndexArrow(0, 233); // 矢印の種類
SetIndexBuffer(0, BuySignalBuffer);

このやり方でも良いのですが、設定が増えると「どこに何を表示しているのか」が分かりにくくなってしまいます。

MQL5では、まず最初に indicator_plots を使って、チャートに「何を、いくつ表示するか」を決めてから作り始めます。

そのあとで、「どんな形にするか(矢印や線など)」や「色・太さ」を、順番にわかりやすく設定していくルールになっています。

MQL5の場合

#property indicator_plots 1//まずはindicator_plotsから宣言する

#property indicator_label1 “Buy Signal”
#property indicator_type1 DRAW_ARROW
#property indicator_color1 clrGreen
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2

このおかげで、MQL5は「何を・いくつ・どう表示するか」が最初からはっきりしているため、初心者でも作りやすく、あとからコードを見ても理解しやすいのが特徴です。

※indicator_color1の「1」は「1番目の描画設定」 を表しています。indicator_color 1の様にスペースが空くとエラーになるのでご注意下さい。

double BuySignalBuffer[];

double BuySignalBuffer[];

サインを表示するためのデータを入れる配列を宣言しています。

この配列は、あとで SetIndexBuffer() を使って、チャートに表示するためのバッファとして登録します。

datetime LastAlertBarTime = 0;

datetime LastAlertBarTime = 0;

アラートの連続発生を防ぐために使われます。

int OnInit()を解説

int OnInit()で動作に
必要な処理を設定

int OnInit() は、インジケーターやEAをチャートにセットしたときに最初に1回だけ実行される関数です。

具体的には、サインを表示するためのデータを入れる箱(バッファ)を用意したり、サインの色や形、大きさを決めたりします。

操作 意味
SetIndexBuffer(0, BuySignalBuffer, INDICATOR_DATA); インディケーターが使用するデータを格納する場所(バッファ)を設定します。これにより、インディケーターが描画に使うデータが格納されます。例えば、BuySignalBufferという配列にデータを保存します。
PlotIndexSetInteger(0, PLOT_ARROW, 233); インディケーターの描画設定を行います。ここでは「233」というコードで矢印を表示する設定をしています。これにより、インディケーターがチャートに矢印を表示します。
return (INIT_SUCCEEDED); 初期化が成功したことを返すためのコードです。この行が実行されることで、インディケーターが正しく準備できたことが示されます。

この中で特に重要になるの「SetIndexBuffer(0, BuySignalBuffer, INDICATOR_DATA);」です。MQL5初心者の方は、SetIndexBuffe()をしっかり理解しておきましょう。

SetIndexBuffe()の引数はSetIndexBuffer(int index, double &buffer[], int type);になります。

引数名 説明
int index 使用するインディケーターのバッファ番号(0から始まる番号)。
double &buffer[] データを格納する配列(バッファ)。インディケーターが表示するデータを格納します。
int type バッファのタイプ。通常、インディケーターのデータを格納するためにINDICATOR_DATAを指定します。

SetIndexBuffer()でBuySignalBuffer[]を登録すると、その配列BuySignalBuffer[]がバッファとして扱われるようになります。

バッファはMetaTraderが常に監視しており、BuySignalBuffer[]に新しい値が入ると、自動的にサインが出されます。

int OnCalculate()を解説

OnCalculate()で
ローソク足の情報が分かる

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[])

OnCalculateは、MQL5でインディケーターを作成する際に使用される、インディケーターの主要な計算関数です。値動きがある毎に、データを更新し、描画するための計算を行います。

OnCalculateは10個の引数が入っており意味は以下の様になっています。

引数名 説明
int rates_total チャートに表示されているバー(ローソク足)の総数。
int prev_calculated 前回計算されたバーの数。最初の計算では0、その後は前回の計算結果を引き継いで計算を行います。
datetime &time[] 各バーの時間情報が格納された配列。
double &open[] 各バーの始値が格納された配列。
double &high[] 各バーの高値が格納された配列。
double &low[] 各バーの安値が格納された配列。
double &close[] 各バーの終値が格納された配列。
long &tick_volume[] 各バーのティックボリューム(価格変動回数)が格納された配列。
long &volume[] 各バーの実際の取引量が格納された配列。
int &spread[] 各バーのスプレッド(買いと売りの価格差)が格納された配列。

MQL5はOnCalculateの引数を順番で見ていますので、表示されているコードと同じ順番で使いましょう。

計算処理を解説

if (rates_total < 4)

if (rates_total < 4) // 3連続陽線なので最低4本必要
return 0;

rates_totalは、現在チャートに表示されているローソク足(バー)の数を示しています。

今回の計算には最低でも4本のローソク足が必要です。もし4本未満の状態で計算を始めると、データが足りなくなりエラーが発生する可能性があります。

そのため、表示されているローソク足が4本未満の場合、計算を開始せずに処理を中断します。

int start = MathMax(prev_calculated - 1, 3);

int start = MathMax(prev_calculated - 1, 3);

「prev_calculated」は前回計算されたローソク足(バー)の数になります。

「prev_calculated - 1」は前回の計算結果の1つ前のバーから計算を再開するという意味になります。これにより、前回計算した場所から次に進めるようになります。

MathMax()は引数の2つの値のうち、大きい方を返す関数であることを意味します。具体的には、prev_calculated - 1(前回の計算での1つ前のバー)と「3」(3本目のバー) のうち、大きい方を選んでいます。

このコードにより、計算は前回の計算が終わった場所の次から始まるか、最低でも3本目のバーから計算が始まるようになります。

例えば、前回計算が2本目のバーで終わった場合、prev_calculated - 1は1になりますが、3と比べると3の方が大きいので、計算は3本目のバーから始まります。

もし前回計算が4本目のバーで終わった場合、prev_calculated - 1は3となり、3本目のバーから計算を再開します。

このようにすることで、計算をする場所が前回計算した場所の次から始まるか、最低でも3本目のバーから計算を始めるようにしています。

if (prev_calculated == 0)

if (prev_calculated == 0)
{
ArrayInitialize(BuySignalBuffer, EMPTY_VALUE);
}

このコードは、インディケーターが初めて計算を行うときに、BuySignalBuffer 配列を空の状態に初期化する処理です。

空の状態にすることで、配列に不要な値や古いデータが残らないようにします。これにより、インディケーターが正しいデータを使って計算できるようになります。

これがないと、BuySignalBuffer 配列に不要な値や古いデータが残り、計算結果が不正確になる可能性があります。

ArrayInitialize()の引数は以下の様になります。


ArrayInitialize(BuySignalBuffer, EMPTY_VALUE);

引数 説明
引数①: 配列 初期化する配列の名前。配列の要素すべてを指定した値で初期化します。例えば、BuySignalBufferなど。
引数②: 初期値 配列の各要素に設定する値。指定された値。(EMPTY_VALUE=初期化されていない状態)
for (int i = start; i <= rates_total - 2; i++)

 for (int i = start; i <= rates_total - 2; i++)
    {
        bool isBullish1 = (close[i] > open[i]);        // 3本目(今確定したバー)
        bool isBullish2 = (close[i - 1] > open[i - 1]); // 2本目
        bool isBullish3 = (close[i - 2] > open[i - 2]); // 1本目
        bool isBullish4 = (close[i - 3] > open[i - 3]); // 4本目(4連続チェック用)

        // ★「ちょうど3連続の時のみ」サインを出す → 4本目が陽線ならスルー
        if (isBullish1 && isBullish2 && isBullish3 && !isBullish4)
        {
            BuySignalBuffer[i] = low[i] - (Point() * 10);

            if (i == rates_total - 2 && LastAlertBarTime != time[i])
            {
                string msg = StringFormat("【アラート】3連続陽線!確定足: %s", TimeToString(time[i], TIME_DATE | TIME_MINUTES));
                Alert(msg);
                PlaySound("alert.wav");

                LastAlertBarTime = time[i];
            }
        }
        else
        {
            BuySignalBuffer[i] = EMPTY_VALUE;
        }
    }

for (int i = start; i <= rates_total - 2; i++)

for (int i = start; i <= rates_total - 2; i++)

上記式は、startからrates_total - 2までのローソク足(バー)を順番に処理するループです。

startは、MathMax(prev_calculated - 1, 3)によって設定され、最初の計算時には最低でも3本目のローソク足から計算が始まります。

初回の計算では、prev_calculatedが0なので、prev_calculated-1は-1になります。その為、MathMax(-1, 3)が適用され、startは3に設定されます。

つまり、3本目のローソク足から計算が始まります。

rates_totalは表示されているローソク足の総数を表し、rates_total-2はローソク足の総数から2を引いた位置を意味します。

例えば、ローソク足が100本の場合、rates_total-2は98本目となり、3本目から98本目までが処理されます。

※-2にする理由

例えば、ローソク足が100本ある場合、「rates_total - 2」という計算によって、98本目までを処理対象とします。

その理由は、一番新しいローソク足(0番目の足)は、まだ値動きの途中で確定していないからです。この「未確定の足」を計算に含めると、後で値が変わってしまう可能性があり、正しい分析やインジケーターの計算ができなくなります。

さらに、「rates_total - 1」も計算から除外することがあります。

これは、インジケーターによっては、最後の1本もまだ安定しないと考え、安全のために計算範囲を「rates_total - 2」までに設定しているからです。

「rates_total - 1」のバーは、確定直後またはまだ完全に処理されていないタイミングだと、データが変動することがあります。これは、ティックごとの更新とバーの確定処理が完全に同期していないために起こる現象です。

bool isBullish1 = (close[i] > open[i]);

bool isBullish1 = (close[i] > open[i]);        // 3本目(今確定したバー)
bool isBullish2 = (close[i - 1] > open[i - 1]); // 2本目
bool isBullish3 = (close[i - 2] > open[i - 2]); // 1本目
bool isBullish4 = (close[i - 3] > open[i - 3]); // 4本目(4連続チェック用)

たとえば、i = 3 の場合は…

インデックス 表すバー コメントの解釈 実際のローソク足
i 3 3本目 4本前のバー
i - 1 2 2本目 3本前のバー
i - 2 1 1本目 2本前のバー
i - 3 0 4本目 最新のバー(未確定) ←基本は使わない

このコードは、4本のローソク足が全て陽線かどうかを確認するためのものです。各行で、close[i](終値)がopen[i](始値)より大きければ陽線(上昇)と判定し、4本のローソク足について陽線かどうかを判断しています。

isBullish1: 今確定したバーが陽線かどうか
isBullish2: 1つ前のバーが陽線かどうか
isBullish3: 2つ前のバーが陽線かどうか
isBullish4: 4つ前のバーが陽線かどうか

boolは、論理型(ブール型)と呼ばれるデータ型で真(true)または偽(false)の2つの値だけを取ります。

bool isBullish = (close[i] > open[i]); // 終値が始値より大きければtrue、そうでなければfalse

if (isBullish1 && isBullish2 && isBullish3 && !isBullish4)

 if (isBullish1 && isBullish2 && isBullish3 && !isBullish4)

このif文では、&&(論理AND演算子)を使って、すべての条件がtrueであるかを確認しています。

&&(論理AND演算子)は、両方の条件がtrueである時だけ、全体がtrueになる演算子です。例えば、A && B の場合、AもBもtrueでないと、結果はtrueになりません。

BuySignalBuffer[i] = low[i] - (Point() * 10);

BuySignalBuffer[i] = low[i] - (Point() * 10);

if (isBullish1 && isBullish2 && isBullish3 && !isBullish4)で全てがtrueの時にバッファ(BuySignalBuffer[i] )に値を入れます。

BuySignalBuffer[i] には、i番目のバーの安値から最小価格変動幅(Point())の10倍を引いた値が格納され、その位置にサインが表示されます。

アラートの処理

if (i == rates_total - 2 && LastAlertBarTime != time[i])
{
string msg = StringFormat("【アラート】3連続陽線!確定足: %s", TimeToString(time[i], TIME_DATE | TIME_MINUTES));
Alert(msg);
PlaySound("alert.wav");

LastAlertBarTime = time[i];
}

このコードは、チャート上で「3本連続の陽線」が確定したタイミングで、トレーダーに知らせるアラート機能です。

仕組みとしては、最後から2本目(1つ前の確定したローソク足)をチェックし、「今回アラートを出す対象のバーの時間」と「前回アラートを出した時間」が異なっているかを確認しています。

もし違っていれば、それは新しいシグナルだと判断し、画面にアラートを表示して音を鳴らします。

また、同じバーでアラートが何度も鳴らないように、「このバーではもうアラートを出した」という情報を記録しています。これにより、アラートは新しいバーが確定してから、次の条件がそろったときにだけ発動するようになっています。

処理内容 説明
if (i == rates_total - 2 && LastAlertBarTime != time[i]) 最後から2番目の確定バーで、かつ前回アラートを出した時間と違う場合に実行する。重複アラートを防ぐ。
string msg = StringFormat("【アラート】3連続陽線!確定足: %s", TimeToString(time[i], TIME_DATE | TIME_MINUTES)); アラート用のメッセージを作成する。3連続陽線が発生した確定足の日時をわかりやすく表示するための文字列。
Alert(msg); 作成したメッセージを画面に表示し、ポップアップ通知を出す。
PlaySound("alert.wav"); 指定したアラート音(alert.wav)を再生し、音で知らせる。
LastAlertBarTime = time[i]; アラートを出したバーの時間を記録し、同じバーでアラートが重複して鳴らないようにする。

エラーが出た時に対処方法

複雑なサインツールを依頼した場合、プログラムの内容がおかしくコンパイルエラーを起こす事があります。

エラー0

通常正常にコンパイル出来た際は、エラーが0になります。

エラー内容

もし何かしらのエラーが発生していた場合、ツールボックスのエラータブに英語でエラー内容が表示されます。

ある程度慣れてくると、どのようなエラーか分かるのですが、初めの内は英語で書かれている為理解が出来ません。

エラーを修正するにはChatGPTやGeminiにエラー内容を正確に伝える必要があるのですが、この英語をいちいち書いていては日が暮れてしまいます。

エラー内容をコピー

そこでまず覚えて欲しいのがエラー内容がコピーできるという事です。

まずはエラー内容の一番下をクリックしてアクティブな状態にします。その状態で「シフトキー」を押しながら一番上のエラー内容をクリックすると全体を選択する事が出来ます。

エラー内容全体を選択した状態で「CTRL+C」でコピーします。

このエラー内容をChatGPTに「CTRL+V」貼り付けます。

エラー内容を張り付ければChatGPTが答えを教えてくれます。

その答えて対して「フルコードで修正して」と伝えてば全て修正してくれます。

エラーが出たら、エラーを張り付ける⇒ChatGPTに作り直してもらう、これを繰り返すだけで基本的にはサインツールが完成します。

MQL5が分からない内はChatGPTやGeminiを信じて作ってもらうしかありません。

このやり方はあくまでも知識が無い時のやり方として覚えておいて下さい。このやり方だけでサインツールを作り続けると後々時間の無駄になります。

AIの選び方や注意点について

サインツールを作成する場合、現時点では ChatGPT や Gemini の無料版だけで対応するのは難しく、有料版の利用がほぼ必須です。

また、精度や作業効率を高めるために、複数のAIを併用することをおすすめします。

無料版だけではほぼ不可能

ある程度しっかりしたサインツールを作るには、AIに何度も質問しながら少しずつ修正を重ねることになります。

当然、使用する回数は多くなります。

ChatGPTもGeminiも無料版には回数制限があるため、途中で制限に引っかかる可能性が高いです。

簡単なものなら無料版でも試せますが、ある程度の規模のサインツールを作るなら、有料版がほぼ必須と考えておきましょう。

最低でも月3000円~6000円が必要になります。

知識が無い内は2つ以上のAIを使い分ける必要がる

AIは便利ですが、間違った内容を自信ありげに出してくることがあります。

しかも同じAIに繰り返し聞くと、同じ方向の間違いを繰り返すことがあります。

そのため、2つ以上のAIを使用する事をおすすめしています。

たとえば、ChatGPTで解決しない問題をGeminiが解決することがありますし、逆のケースもあります。

1つのAIだけに頼ると同じ場所でずっと詰まってしまいます。

経験上、複数のAIを使い分けたほうが結果的に早く進むことが多いです。

AIの特徴

あくまでも私が感じたAIの特徴になります。

ChatGPTは頑固で融通が利きません。

しかし伝えたことは基本的に忠実に守ってくれます。頑固なので、出来ない問題が発生した場合は、間違った同じ内容の答えを延々に回答し続けます。

Geminiは融通が利くので、できない問題を別視点から解決してくれるます。しかし言った事を守らない、勝手にコードの内容を変えるなど問題も多く、細かく伝える必要がある問題児です。

クロードはコーディングで最も優れていると聞きますが、MQL4/MQL5に関してはそこまで優れていると感じません。期待値が高かったかもしれませんが、ChatGPTとGemini同じく馬鹿な回答をします。

【重要】知識ゼロのまま作り続けるのは苦行

MQL4・MQL5の知識がなくてもサインツールは作れます。ただ、知識ゼロのままでは後々つらくなるので、少しずつ学んでいくことをおすすめします。

何か問題が起きたとき、AIに質問すれば回答と修正コードを出してくれます。

しかし ChatGPTやGeminiは、間違ったことを平然と言う場合があります。

ある程度の知識がついてくると、その回答が正しくないと気づけるようになります。

これが大きなポイントです。

AIを100%信じて作業を続けると、こんな悪循環に陥ることがあります。

問題発生 → 修正依頼 → 間違ったコードで修正 → 問題は解決せず → 再度依頼 → さらに間違いが重なる → 最終的に手がつけられないコードの完成

この連鎖にはまると、遠回りが増えてストレスも積み重なっていきます。

そこで大切なのが、「本当にそうなのか?」と一度立ち止まって考える習慣です。

最初は細かい内容が分からなくて構いません。

「言っていることに筋が通っているか」を意識するだけで十分です。

おかしいと感じたら、別のAIにセカンドオピニオンを求めてみましょう。

GeminiやClaudeに「ChatGPTがこう言っているけど、これは正しい?」と聞くと、違う視点からの回答が得られます。

AIの回答に疑問を持ち、自分で考えることを繰り返すうちに、少しずつ知識が身についていきます。

AIに頼り切っていると、この知識が育ちません。「考える癖をつける」ことが、遠回りを減らす一番の近道です。

AIでサインツールを作る時によくある問題点

ここでは、AIでサインツールを作るときに起きやすいトラブルをまとめています。事前に知っておくだけでも、かなり進めやすくなります。

更新頻度と重さの問題

まず「ティック」という言葉を覚えてください。ティックとは、価格が1回動くたびに発生する更新の単位です。インジケーターはそのたびに計算が走ることがあります。

ティックの回数は銘柄や時間帯によって異なりますが、多いときは1秒に数十回、活発な場面では100回前後以上になることもあります。

問題になるのが、ティックが来るたびに全期間の足を毎回計算し直す作りです。

特に1分足のように足の本数が多い場合、動作が極端に重くなります。チャートをスライドしたときに重く感じる場合、その多くは不要な再計算が原因です。

本来、一度確定した過去のサインをわざわざ毎回作り直す必要はありません。

考え方としては、

「過去の足はそのまま」

「最新の足だけ確認する」

で十分です。

しかしAIに何も伝えないと、全体を毎回確認するシンプルなコードで書いてきます。

サインだけならまだしも、移動平均線なども表示するツールになると、ティックごとに全部描き直す作りでは最悪フリーズすることもあります。

このときAIに伝えるべき重要なキーワードが、「初回は全体、以降は差分で」です。

起動直後に多少重たくなるのは、避けられません。

ただしそれ以降を差分処理にすることで、新しい足だけを処理する形にできます。

これだけでも動作の重さはかなり改善します。重いと感じたらまず差分処理を疑ってください。

バッファとオブジェクト問題

サインは基本的に「バッファ」か「オブジェクト」で作られます。

比較項目 バッファ オブジェクト
動作の重さ 軽い 重くなりやすい
ティックが来るたびの負荷 数値を入れ替えるだけなので負荷が小さい 作成・移動・削除の処理が増えると負荷が大きくなりやすい
大量に使ったとき 比較的耐えやすい 数が増えるほど重くなりやすい
チャート表示の負担 描画は比較的効率的 1個ずつ管理するため表示負担が増えやすい
初心者向けの覚え方 「数字を並べて描くので軽め」 「部品をたくさん置くので重め」

AIにサインの形や位置を細かく指定すると、扱いやすいオブジェクトを選ばれやすくなります。

しかし、全期間に大量のサインを出すツールでオブジェクトを使うと、非常に重くなりやすいです。

どうしてもオブジェクトで作る場合は、現在画面に見えている範囲だけにサインを表示し、スライドしたらその範囲だけ再表示するなど、表示範囲を制限する対策が必要です。

基本的にはサインを「バッファ」で作ることをおすすめします。

AIに依頼する前に「サインはバッファで作ってください」と指定しておくだけで、無駄な修正をかなり減らせます。

表示期間の問題

AIに表示期間を指定しないと、全期間でサインが表示される設計になり、チラつきが起きやすくなります。

表示されるサインが1万個と100個では処理量がまったく異なり、数が多いほど再描画に時間がかかって一瞬映らない瞬間が生まれます。これがチラつきの正体です。

対策としては、「直近〇〇本だけ表示する」「古いサインは非表示にする」といった表示期間の制限を加えるだけで大きく改善します。

なお、表示期間を全体から10日分に絞っても、動作が極端に軽くなるわけではありません。

MT5は最大表示本数分のデータを内部で保持し続ける仕様のためです。

表示期間の制限はあくまでチラつき対策として有効とご理解ください。

ボタンなどUI問題

ボタンなどのUIを1から指定した場合、思ったようなものをなかなか作ってくれません。

これはどのAIを使っても同じです。

作り方が分からない内は「完全にガチャ」になります。気に入る形になるまで、何度でも作ってもらいましょう。

気に入った形になったら必ず保存して下さい。

以降そのコードをAIに読み込ませます。

その際にまずは、「以下のコードをコード1と呼びます」と書いて、コードを貼り付けます。

その後、今作っているコードを貼り、以下のコードで使用するボタンはコード1と同じ形にしてと伝えれば、同じ形のボタンを作ってくれます。

UIに関してはどれだけストックがあるかが重要になります。

ヒストリ問題

ヒストリとは、過去のチャートデータのことです。

初めて開く通貨ペアでW1(週足)などを表示すると、データがまだ無い場合が多く、そのときはサーバーから過去データを取得します。

一方で、1分足(1M)や1時間足(1H)は、最初からデータが揃っていることが多いです。

普段使わない通貨ペアで週足を開くと、チャートが左から右へゆっくり伸びていくことがあります。これはサーバーからデータを読み込んでいる途中の状態です。

例えば、1時間足でサインツールを使う場合は、すでにデータが揃っているため問題なく動作します。

しかし、その直後に週足を開くと問題が起きることがあります。

仮にサインツールが「直近1年分だけ表示する」仕様だとします。週足を開いた時点ではデータがまだ無いため、ツールは「データが存在しない」と判断してしまいます。

その結果、本来表示されるべきサインが全く出なかったり、逆に全期間に表示されてしまうことがあります。

一度チャートを開いてデータが取得されれば、その後は保存されるので問題は起きません。ただし、初回だけはこの「ヒストリ問題」が発生します。

この仕組みを理解している人は、データの取得が終わった後にサインツールを再起動すれば正常に使えると分かっていますが、知らないと単なるバグに見えてしまいます。

サインツールを正しく使うためにも、このヒストリ問題があることは覚えておいてください。

【初心者向け】MQL4/MQL5の学習方法!サインツールの中身を理解しよう

MQL4とMQL5の学習方法は同じで、ChatGPTやGeminiに分からない箇所を聞くだけですが、MQL4とMQL5を初めて学習される方は「全部分からない」状況から始まります。

その場合、まずはChatGPTやGeminiになるべく簡単なコード(陽線3つでサイン&アラート)などで作ってもらい、動作確認を行います。

動作が問題無ければその作ってもらったコードをに対して以下の内容で作り変えてもらいます。

学習様に最適な言葉

AIへの依頼

以下のコードを変数名だけ分かりやすくして 例えば陽線はyousenの様に日本人が理解しやすくして

また各行に初心者が理解できるように簡潔なコメントを付けて

{}にコメントはつけなくていい

最適な言葉の解説

MQL4とMQL5を始めて学習する際にまず迷うのが変数名です。

変数名は基本的に分かりやすく短めの「英単語」を使用しますが、この変数名が英語なので頭の中でイメージが付きにくくコードを見ていてしんどくなります。

コードが長くなると、この変数は何だっけ?とどうしてもなります。

この変数名を変更するだけでも学習効率が上がります。

また、各行にコメントを付けてもらうことで、学習の効率が更に上がります。

実際に作って貰ったコードになります。


//+------------------------------------------------------------------+
//| 3連続陽線でサインを出すバージョン                                |
//+------------------------------------------------------------------+
#property indicator_chart_window                // チャートのメイン画面にインジケーターを表示する
#property indicator_buffers 1                   // 使用するバッファの数は1つ
#property indicator_plots 1                     // 描画するプロットの数は1つ
#property indicator_label1 "Buy Signal"         // インジケーターの名前ラベル
#property indicator_type1 DRAW_ARROW            // 描画タイプは矢印
#property indicator_color1 clrGreen             // 矢印の色は緑
#property indicator_style1 STYLE_SOLID          // 線のスタイルは実線
#property indicator_width1 2                    // 矢印の太さは2

double kaiSainBuffer[];          // 買いサインの矢印を描画するためのバッファ配列
datetime zenkaialertJikan = 0;   // 同じバーで何度もアラートを鳴らさないための前回時刻記録

int OnInit()
{
    SetIndexBuffer(0, kaiSainBuffer, INDICATOR_DATA); // バッファ0番にkaiSainBufferを登録する
    PlotIndexSetInteger(0, PLOT_ARROW, 233);          // 矢印の形を233番(↑マーク)に設定する
    return (INIT_SUCCEEDED);                          // 初期化が成功したことをMT5に返す
}

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[])          // 各バーのスプレッドの配列
{
    if (rates_total < 4)                                      // バーが4本未満なら判定できないので処理を中断する
        return 0;                                             // 0を返して終了する

    int keisanKaishiIndex = MathMax(prev_calculated - 1, 3); // 計算を始めるバーの位置を決める(再計算は1本前から)

    if (prev_calculated == 0)                                 // 初回起動または全バー再計算の場合
        ArrayInitialize(kaiSainBuffer, EMPTY_VALUE);          // バッファ全体をEMPTY_VALUE(空)で初期化する

    for (int i = keisanKaishiIndex; i <= rates_total - 2; i++) // 計算開始位置から最新確定足まで1本ずつ処理する
    {
        bool yousen1 = (close[i]     > open[i]);              // 直近1本目(最新確定足)が陽線かどうか判定する
        bool yousen2 = (close[i - 1] > open[i - 1]);          // 直近2本目が陽線かどうか判定する
        bool yousen3 = (close[i - 2] > open[i - 2]);          // 直近3本目が陽線かどうか判定する
        bool yousen4 = (close[i - 3] > open[i - 3]);          // 直近4本目が陽線かどうか判定する(4連続除外用)

        // ちょうど3連続陽線の時だけサインを出す(4本目も陽線なら4連続なのでスキップ)
        if (yousen1 && yousen2 && yousen3 && !yousen4)        // 1〜3本目が陽線かつ4本目が陰線の場合
        {
            kaiSainBuffer[i] = low[i] - (Point() * 10);      // 安値より少し下の位置に矢印をセットする

            if (i == rates_total - 2 && zenkaialertJikan != time[i]) // 最新確定足かつ同じバーで未通知なら
            {
                string alertMeseji = StringFormat("【アラート】3連続陽線!確定足: %s",
                                     TimeToString(time[i], TIME_DATE | TIME_MINUTES)); // アラート用の文字列を作成する
                Alert(alertMeseji);              // 画面にポップアップアラートを表示する
                PlaySound("alert.wav");          // アラート音を鳴らす
                zenkaialertJikan = time[i];      // 今回通知したバーの時刻を記録して二重通知を防ぐ
            }
        }
        else
        {
            kaiSainBuffer[i] = EMPTY_VALUE;      // 条件を満たさない場合はそのバーのサインを消す
        }
    }

    return rates_total; // 今回計算したバー数を返す(次回呼び出し時のprev_calculatedになる)
}

変数の変更に関しては好みがあるので、何とも言えませんが、各行にコメントを付ける事で理解しやすくなります。

初めの内はコメントを見ながら、理解される事をおすすめします。

プログラムに触れた事が無い方は

プログラム自体が初めての方は、先に基礎を学ぶ事をおすすめします。

C++を学習する

プログラム初心者の方はいきなりMQL4やMQL5を学ぼうとしてもチンプンカンプンになると思います。実際に「変数」・「関数」・「データ型」・「if, for, while, switch 」などの基礎知識は避けては通れません。

プログラムの基礎を学ぶなら「C++」がおすすめになります。

C++はMQL4やMQL5に近いプログラム言語です。

MQL4やMQL5がC++ に近い理由
  • 構文が C++ とほぼ同じ
  • データ型(int, double, bool など)が C++ と同じ
  • ポインタは使えないが、配列や参照渡し (&) は使える
  • if, for, while, switch などの制御構文も C++ と同じ
  • C++ に比べて低レベルの操作(メモリ管理など)は不要

C++であれば「C++ 基礎」と検索すればいくらでも学べるサイトが見つかります。

綾瀬 文也

10年以上のFXトレード経験を持ち、チャート分析と戦略構築を専門とするトレーダー。マーケットの変動を的確に捉え、リスク管理を徹底することで安定した収益を実現。現在はpokyun企画代表として活動

綾瀬 文也をフォローする
無料インジケーター

コメントをお待ちしています