【MQL4】グローバル変数とローカル変数の違い|EAでの使い分けを実例コードで解説

スーツ姿のデグーマウスがMT4 EAのコードを指しながら解説しているイラスト。ぷろぐらむFXのデフォルトアイキャッチ。
EAを自作してみよう
スポンサーリンク

MQL4でEAを作成していると、 「なぜこの変数は先頭に書くのか?」 「関数内に書いた変数が他で使えないのはなぜか?」 と疑問に感じることはありませんか?

これはグローバル変数ローカル変数の違いを理解していないことが原因です。

本記事では、EAの実例コード(新バー判定)を使いながら、 MQL4におけるグローバル変数とローカル変数の違い・使い分けを 初心者向けに解説します。

グローバル変数とローカル変数の違いとは?

プログラミングをしたりソースコードを見ていると、 「なぜ変数が先頭と関数の中に分かれているのだろう?」 と疑問に思ったことはありませんか?

これは グローバル変数ローカル変数 という 2種類の変数の違いによるものです。

MQL4のソースコードでグローバル変数とローカル変数の宣言位置の違いを示した図

上部の赤枠が グローバル変数、 下部の赤枠が ローカル変数 です。

まずは違いを一覧で確認してみましょう。

項目ローカル変数グローバル変数
宣言場所関数の中関数の外(先頭)
使える範囲その関数内のみプログラム全体
値の保持処理が終わると初期化EA終了まで保持
主な用途一時的な判定・計算状態の記憶・前回値保持

グローバル変数、ローカル変数の命名由来

「グローバル(global)」は 地球全体・広い範囲 を意味します。 プログラミングでは 関数を超えてプログラム全体で使える という意味になります。

一方「ローカル(local)」は 特定の場所・限定された範囲 を意味し、 特定の関数内でのみ使える 変数を指します。

グローバル変数はプログラム全体で使え、
ローカル変数は宣言した関数内でしか使えない

では、先ほどのソースコードをもう一度見てみましょう。

MQL4でグローバル変数とローカル変数のスコープを示したコード例

[G_prevtime] は関数の外で宣言されているため どの関数からでも参照できるグローバル変数です。

一方 [L_prevtime] は testLog() 関数内で宣言されているため、 その関数内でしか使用できません

スポンサーリンク

EAでグローバル変数とローカル変数を使い分ける場面

まず、大前提としてローカル変数が基本形の変数です。基本はローカル変数を使うようにしましょう。グローバル変数はあくまでローカル変数では実現が難しい場合に使うようにします。

では、ローカル変数では実現が難しい場合(グローバル変数の使用用途)は大きく2つあります。

①プログラム全体で参照したい

グローバル変数はプログラム全体に関わる=プログラム全体どこからでも参照できるという事になります。ですので、A関数でグローバル変数に値を入れて、それをB関数でチェックし、それをC関数で出力という感じでどこからでも参照したり値の変更ができます。

ですので、複数の関数で使う値がある場合はグローバル変数にしたりします。
※ただし、値を引数で渡せばグローバル変数にする必要はないので作り手でこの辺はばらけます

なお、EAでは「プログラム全体で参照できる変数」として、 externinput を使うケースもあります。

これらは見た目や使い方がグローバル変数と似ていますが、 役割は「EAの外から値を設定するための変数」であり、 純粋なグローバル変数とは目的が異なります。

MQL4のinputとexternの違いと使い分け

②値を覚えておきたい

グローバル変数は、EAを終了させない限り値が無くなりません。(初期化されません)

ローカル変数の場合、例えばOnTick()内で変数を宣言していた場合、値動きの処理が終わったあと値は初期化されます。

ですので、値を覚えておきたい(前回のエントリー状況等の)場合はグローバル変数を使います。

👉 「前回の状態を覚えておく必要があるか?」が、
グローバル変数を使うかどうかの判断基準になります。

グローバル変数の落とし穴

一見グローバル変数は、プログラム全体で使えたり記憶できる変数としてスペシャルな変数に見えるのですが、悪い部分が存在します。

①可読性が落ちる

グローバル変数を使うと、プログラムの読みやすさ『可読性』が低下します。短いプログラムなら可読性は低下しませんが、長いプログラムになればなるほど可読性が低下します。

このグローバル変数はどこで使われて、どこで値を入れているのか?が一目でわからなためです。

ローカル変数だと、関数内で完結するのでどこで使われてどこで値を入れているのかも全て関数内なので読みやすさは歴然です。

②影響箇所が増える

グローバル変数を使うと、プログラムを修正する際等の影響箇所が増えます。ここでグローバル変数に値入れてるけどちょっと変更したいなと思って、違う値を入れるとグローバル変数を使っている全ての処理に影響してきます。

思いもしないバグを引き起こす一番の原因になります。ですので、グローバル変数の値を変更したり、いらない部分を消したりとメンテナンスする際はプログラム全体を見直しながら修正しないといけません。

ローカル変数だと、入れる値を変更しようが変数を削除しようが影響するのは関数内だけなので影響箇所は限定されます。

社会人時代、私は主に既存プログラムの改修がメイン業務でしたが、グローバル変数はシステム全体に影響を及ぼすので使用禁止なんて案件もありました。

③初期化忘れが起きる

グローバル変数を使うと、今そのグローバル変数に何が入っているのかを正確に理解しておく必要があります。グローバル変数は値を覚えておくといった特性がある反面、値を絶対に初期化しません。(私たちが自発的に行う必要があります)

ですので、値の初期化忘れでシステムにバグが生じるという事も日常茶飯事です。

実際に動かして確認してみよう

上記の内容を踏まえグローバル変数を使っていきましょう。適切に使えばとても便利な変数です。

ここでは、同じロジックを ローカル変数版/グローバル変数版で実行し、 挙動の違いを実際に確認してみます。

まずは、簡単なソースコードを実際に動かして確認してみましょう。

//+------------------------------------------------------------------+
//|                                                   practice_1.mq4 |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

input int ptn_global = 0;

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

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){
//---
   //テストログ関数を呼び出す
   testLog(); 
}
  
bool testLog(){

   datetime L_prevtime=0;
   
   if(ptn_global==0){
      if(Time[0] != L_prevtime){
         L_prevtime = Time[0];
         Print("新しいローソク足が描画されましたL:"+L_prevtime);
      }
   }else{
      if(Time[0] != G_prevtime){
         G_prevtime = Time[0];
         Print("新しいローソク足が描画されましたG:"+G_prevtime);
      }
   }
   return true;

}
//+------------------------------------------------------------------+

こちらは、チャートのローソク足が新しくできたら操作履歴にログを出力するというプログラムになります。

グローバル変数の『G_prevtime』とローカル変数の『L_prevtime』名以外は全く同じの処理をtestLog()関数内で行っています。

パラメータのptn_globalが0の時はローカル変数を使った場合の処理、1の時はグローバル変数を使った場合の処理を行うようにしています。

結果はどうなるでしょうか。

スポンサーリンク

ローカル変数の場合

ローカル変数を使用した新バー判定で毎ティックごとにログが出力される例

結果は、ローソク足が描画されたときにログが出力されておらず値動きのたびにログが出力されました。

理由は簡単で、

      if(Time[0] != L_prevtime){
         L_prevtime = Time[0];
         Print("新しいローソク足が描画されましたL:"+L_prevtime);
      }

Time[0]の値をL_prevtimeにセットしていますが、これは値動きが終わる度に、初期化されてしまうのでif文で判別している箇所は総じて[最新のローソク足の時間 != 0]となってしまうからです。なので値動きがある度にログが出力されてしまうんですね。

グローバル変数の場合

グローバル変数を使用した新バー判定でローソク足確定時のみログが出力される例

結果は、ローソク足が描画されたときにしっかりログが出力されていますね。

こちらは、

      if(Time[0] != G_prevtime){
         G_prevtime = Time[0];
         Print("新しいローソク足が描画されましたG:"+G_prevtime);
      }

Time[0]の値をG_prevtimeにセットしていますが、これは値動きが終わっても初期化されずしっかり時間を覚えているのでif文でしっかり判別できます。

trueとなる場合は[最新のローソク足の時間 != 1つ前のローソク足の時間]となります。
※前回のチェックから新しいローソク足が描画された場合

falseとなる場合は[最新のローソク足の時間 != 最新のローソク足の時間]となります。
※前回のチェックからローソク足がまだ描画されていない場合

グローバル変数とローカル変数の違いだけでこうも結果が変わってしまうんですね。


❓ グローバル変数・ローカル変数に関するよくある質問【MQL4 FAQ】

💬 EA開発初心者がつまずきやすい「変数の使い分け」に関する疑問をまとめました。

グローバル変数とローカル変数の一番の違いは何ですか?

一番の違いは「使える範囲」と「値を保持するかどうか」です。
ローカル変数は宣言した関数内でのみ使え、処理が終わると初期化されます。
グローバル変数はプログラム全体から参照でき、EAを終了するまで値を保持します。

なぜEAではローカル変数が基本と言われるのですか?

ローカル変数は影響範囲が関数内に限定されるため、コードの可読性が高く、
修正やデバッグ時に想定外の影響が出にくいからです。
EAではまずローカル変数を使い、必要な場合のみグローバル変数を使用します。

グローバル変数はどんなときに使うべきですか?

「前回の状態を覚えておきたい」「複数の関数で同じ値を共有したい」場合に使います。
例えば、新バー判定や前回エントリー情報の保持などは、グローバル変数が適しています。

グローバル変数を使うと何が問題になりますか?

可読性が下がり、どこで値が変更されているか分かりにくくなります。
また、1か所の修正がプログラム全体に影響しやすく、バグの原因になりやすい点がデメリットです。

externやinputはグローバル変数と同じですか?

見た目は似ていますが役割は異なります。
externやinputはEAの外から設定値を変更するための変数であり、
純粋なグローバル変数とは目的が違います。

さいごに

以上が、MQL4におけるグローバル変数とローカル変数の違いと使い分けについての解説です。

グローバル変数とローカル変数はプログラミングをするうえで重要になってきますので是非覚えておきましょう。

ここまでで、グローバル変数とローカル変数の違い、 そして「どこに変数を書くかで役割が変わる」という点が理解できたと思います。

次のステップとしては、 ローカル変数を使って処理をひとまとめにする「関数」を理解すると、 EAのコード構造が一気に見やすくなります。

EAプログラミング入門 STEP6|関数でコードを整理する


✅EA開発初心者の方はこちらもチェック!

MT4やMQL4の知識がなくても大丈夫!
当サイトでは、プログラミング未経験者でも分かるEA開発の基本から、サンプルコードを使った実践的なチュートリアルまで多数ご用意しています。

ChatGPTやEAつくーるでのEAの作り方に興味がある方は是非参考にしてください。

コメント

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