1. MQL5のOnTickとは何か
1.1 OnTickの基本役割
OnTick は、MQL5でEA(Expert Advisor:自動売買プログラム)を開発する際に最も重要な関数の一つです。
この関数は 価格のティック(Tick:価格更新イベント)を受信した瞬間に自動実行されるイベント関数 です。
MetaTrader 5のEAは、通常のプログラムのように「順番に処理を実行する構造」ではなく、イベント駆動型(Event-driven) という仕組みで動きます。
イベント駆動とは、特定の出来事が発生したときにプログラムが動く仕組みです。
EAの場合、最も重要なイベントが 価格更新(Tick) です。
そのため、EAの売買ロジックの大部分は OnTick関数の中に記述される のが一般的です。
基本構文は非常にシンプルです。
void OnTick()
{
// ティック受信時に実行される処理
}
例えば、ティックを受信したときにログを出力するだけの最小コードは次のようになります。
void OnTick()
{
Print("Tick received");
}
このコードは、価格が更新されるたびに 「Tick received」 とログに出力されます。
EA開発では、OnTickの内部で次のような処理を行うのが一般的です。
- インジケーターの値を取得する
- 売買条件を判定する
- 条件を満たした場合に注文を出す
- ポジションを管理する
つまり EAの意思決定の中心がOnTick です。
1.2 ティックとは何か(初心者向け)
OnTickを理解するためには、まず ティック(Tick) の概念を理解する必要があります。
ティックとは、市場から新しい価格が届いた瞬間のイベントのことです。
簡単に言うと、価格が更新されたタイミングです。
例えば次のような変化が起きた場合、ティックが発生します。
| 時刻 |
Bid価格 |
| 10:00:01 |
150.100 |
| 10:00:02 |
150.101 |
| 10:00:03 |
150.101 |
| 10:00:04 |
150.102 |
このように価格が変化すると、そのたびに 新しいティックが発生します。
重要なポイントは次の通りです。
- ローソク足とは別の概念
- ローソク足は一定時間の価格をまとめたもの
- ティックは リアルタイムの価格更新
つまり、1本のローソク足の中でも 数百〜数千ティック が発生することがあります。
市場の状況によってティック頻度は大きく変わります。
| 市場状況 |
ティック頻度 |
| ロンドン市場 |
非常に多い |
| ニューヨーク市場 |
多い |
| 東京市場 |
中程度 |
| 週末 |
ほぼ無し |
ティックが発生すると、そのたびに OnTickが呼び出されます。
1.3 EAの中でのOnTickの位置
MQL5のEAは、通常次のようなイベント関数で構成されます。
OnInit()
OnTick()
OnDeinit()
それぞれの役割は次の通りです。
| 関数 |
役割 |
| OnInit |
EA起動時に1回実行 |
| OnTick |
価格更新ごとに実行 |
| OnDeinit |
EA終了時に実行 |
処理の流れは次のようになります。
- EAをチャートにセット
- OnInit() が実行される
- 価格が更新される
- OnTick() が実行される
- ティックが来るたびにOnTickが繰り返される
つまり、EAが実際にトレード判断を行うタイミングは OnTickが呼ばれた瞬間です。
よくある誤解(つまずきポイント)
初心者がよく誤解するポイントがあります。
① OnTickは一定時間ごとに動くわけではない
OnTickはタイマーではありません。
価格更新がない限り実行されません。
例
この場合、OnTickはしばらく呼ばれないことがあります。
② ティックはローソク足とは別
初心者はよく
「1分足が更新されたらOnTickが動く」
と考えがちですが、これは誤りです。
実際は
という仕組みです。
③ OnTickに重い処理を書くとEAが遅くなる
ティックは 非常に高頻度で発生します。
通貨ペアによっては
OnTickの処理が重いと
といった問題が発生します。
よくある失敗
EA初心者が最初に起こしやすいミスがあります。
無限注文バグ
void OnTick()
{
if(condition)
{
OrderSend(...);
}
}
このコードは、条件がtrueの間 毎ティック注文を出してしまいます。
結果
という事故が起きることがあります。
そのため通常は
などを入れて制御します。
2. OnTickの基本構文と使い方
2.1 OnTick関数の基本構文
MQL5における OnTick関数 は、EA(Expert Advisor)専用のイベント関数です。
市場から 新しいティック(価格更新)が届いた瞬間 に自動的に実行されます。
基本構文は次の通りです。
void OnTick()
{
// ティック受信時に実行される処理
}
ポイントは次の3つです。
- 戻り値は必ず
void
- 引数は持たない
- EAでのみ使用できる
インジケーターやスクリプトではOnTickは使用できません。
これは EAがリアルタイム価格イベントに反応するプログラムだからです。
2.2 最小構成のOnTickコード
最もシンプルなOnTickの例です。
void OnTick()
{
Print("New Tick");
}
このコードをEAとしてチャートにセットすると、
価格が更新されるたびにログへ出力されます。
ログ例
New Tick
New Tick
New Tick
このように ティックごとにOnTickが実行される ことを確認できます。
2.3 現在価格を取得する例
EAでは通常、OnTick内で現在価格を取得します。
void OnTick()
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
Print("Bid:", bid, " Ask:", ask);
}
ここで使われている主な要素は次の通りです。
| 要素 |
説明 |
_Symbol |
現在の通貨ペア |
SYMBOL_BID |
売値 |
SYMBOL_ASK |
買値 |
このコードは リアルタイムの価格を取得する基本パターンです。
EAの多くは次の流れになります。
- 現在価格取得
- インジケーター取得
- 売買条件判定
- 注文送信
2.4 売買条件を書く基本パターン
OnTickの典型的な構造は次の形です。
void OnTick()
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(bid > 150.000)
{
Print("Buy condition");
}
}
実際のEAではここに
などのインジケーター条件が追加されます。
例
void OnTick()
{
double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(price > 150.000)
{
// ここに注文処理を書く
}
}
2.5 EAの典型構造(実践パターン)
実際のEAは次のような構造になります。
void OnTick()
{
CheckSignal();
ManagePosition();
}
関数分割の例
void CheckSignal()
{
// エントリー判定
}
void ManagePosition()
{
// 利確や損切り管理
}
このようにすることで
というメリットがあります。
つまずきやすいポイント
初心者がOnTickでよく間違える部分があります。
① OnTickは自分で呼び出さない
OnTickは 自動実行されるイベント関数です。
次のように書く必要はありません。
OnTick();
これは 完全に不要です。
② OnTickは複数作れない
次のようなコードはエラーになります。
void OnTick()
{
}
void OnTick()
{
}
EA内では OnTickは1つだけ 定義できます。
③ 重い処理を書きすぎない
ティックは非常に多く発生します。
通貨ペアによっては
そのため次のような処理は注意が必要です。
これらは パフォーマンス問題の原因になります。
よくある失敗
初心者が最初に作るEAでよく起きる問題があります。
毎ティック注文バグ
void OnTick()
{
if(signal)
{
OrderSend(...);
}
}
このコードでは、
条件がtrueの間ずっと注文を出し続けます。
結果
という事故になります。
対策としては
などを行います。
3. OnTickが呼び出されるタイミング(ティック処理の仕組み)
3.1 OnTickは価格更新イベントで実行される
MQL5の OnTick関数 は、市場から新しいティック(価格更新)が届いた瞬間に実行されます。
つまり、OnTickは 時間ではなく価格変化に反応するイベント関数です。
EAの実行フローは次のようになります。
価格更新(Tick発生)
↓
MetaTraderがイベント検出
↓
OnTick() が呼び出される
↓
EAの売買ロジックが実行される
この処理は ティックごとに繰り返されます。
例えば、EURUSDのような流動性の高い通貨では
OnTickが実行されることがあります。
逆に、流動性が低い時間帯では
OnTickが呼ばれない場合もあります。
重要なのは次の点です。
OnTickは「一定時間ごと」に動く関数ではない
ということです。
3.2 ティックとローソク足の違い
初心者が最も混乱しやすいポイントが
ティック(Tick)とローソク足(Bar)の違い
です。
| 概念 |
内容 |
| ティック |
価格が更新された瞬間 |
| ローソク足 |
一定時間の価格データ |
例えば 1分足チャートの場合でも、内部では次のような動きが発生しています。
10:00:01 150.100
10:00:01 150.101
10:00:02 150.100
10:00:03 150.102
10:00:05 150.101
このすべてが ティックです。
しかし、1分足では
10:00〜10:01
の価格をまとめて 1本のローソク足として表示します。
つまり
- OnTick → ティックごと
- インジケーター → 通常はバー単位
という違いがあります。
この違いを理解していないと、次のような誤解が生まれます。
「1分足更新でEAが動く」
これは正しくありません。
実際には
価格更新のたびにEAは動いています。
3.3 市場状況によるティック頻度の違い
OnTickの実行頻度は 市場の流動性によって大きく変わります。
一般的な目安は次の通りです。
| 市場 |
ティック頻度 |
| ロンドン市場 |
非常に多い |
| ニューヨーク市場 |
多い |
| 東京市場 |
中程度 |
| 週末 |
ほぼゼロ |
特に次のタイミングではティックが急増します。
このとき OnTickの実行回数が急増します。
そのためEAでは
が重要になります。
3.4 ティックが来ないケース
初心者がよく疑問に思うのが
「EAが動かない」
という問題です。
その原因の多くは ティックが発生していないことです。
次のような状況ではOnTickは実行されません。
- 市場が閉まっている(週末)
- 流動性の低い銘柄
- デモ口座のデータ遅延
- チャートが停止
つまり
OnTickはティックが来ないと絶対に実行されない
という仕組みです。
もし定期処理が必要な場合は、MQL5では次のイベントを使います。
OnTimer()
これは 指定時間ごとに実行されるイベントです。
つまずきポイント
OnTickの仕組みで初心者がよく混乱する部分があります。
① ティック数はバックテストと違う
バックテストでは
によってティック数が変わります。
そのため
で OnTick回数が一致しないことがあります。
これは正常な動作です。
② 高速EAはティック数の影響を受ける
スキャルピングEAなどでは
が結果に大きく影響します。
環境によって
が変わることがあります。
よくある失敗
ティック処理を理解せずにEAを書く
初心者がよく書くコードの例です。
void OnTick()
{
if(signal)
{
OrderSend(...);
}
}
このコードは
ティックごとに注文を出す
ため、次の問題が起きます。
- 同じ条件で連続注文
- 数秒で大量ポジション
- 証拠金破綻
実際のEAでは次のような制御が必要です。
- 新バー判定
- ポジションチェック
- エントリー回数制御
4. OnTickを使ったEAの基本構造(実践コード例)
4.1 EAの基本構造(OnInit・OnTick・OnDeinit)
MQL5のEAは、通常次の3つのイベント関数で構成されます。
| 関数 |
役割 |
| OnInit |
EA起動時に1回実行 |
| OnTick |
ティックごとに実行 |
| OnDeinit |
EA終了時に実行 |
基本的なEAのテンプレートは次のようになります。
int OnInit()
{
Print("EA started");
return(INIT_SUCCEEDED);
}
void OnTick()
{
// 売買ロジック
}
void OnDeinit(const int reason)
{
Print("EA stopped");
}
処理の流れは次の通りです。
- EAをチャートにセット
- OnInit()が実行される
- ティックが到着
- OnTick()が実行される
- EAを外すと OnDeinit()が実行される
実際のトレード判断は OnTickの中で行う のが基本です。
4.2 シンプルなEAの例(価格条件)
最も簡単なEAの例を示します。
void OnTick()
{
double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(price > 150.000)
{
Print("Price is above 150");
}
}
このEAは
という基本構造になっています。
EA開発ではまずこの 基本パターン を理解することが重要です。
4.3 インジケーターを使ったEAの基本形
実際のEAではインジケーターを使って売買判断を行います。
例として 移動平均(MA) を使う場合の構造を示します。
int maHandle;
int OnInit()
{
maHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);
return(INIT_SUCCEEDED);
}
void OnTick()
{
double maBuffer[];
CopyBuffer(maHandle, 0, 0, 1, maBuffer);
double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(price > maBuffer[0])
{
Print("Buy signal");
}
}
処理の流れ
- OnInitでインジケーター作成
- OnTickで値を取得
- 条件判定
この構造は多くのEAで使われています。
4.4 EAの実務的な構造(おすすめパターン)
実際のEAでは、OnTickにすべてを書くとコードが非常に読みにくくなります。
そのため通常は 関数分割 を行います。
例
void OnTick()
{
CheckEntry();
ManagePosition();
}
エントリー判定
void CheckEntry()
{
// エントリー条件
}
ポジション管理
void ManagePosition()
{
// 利確・損切り処理
}
この設計にすると
というメリットがあります。
つまずきポイント
① OnTickに全部書く
初心者が最初に書くEAは次のようになります。
void OnTick()
{
// 100行以上のコード
}
この構造では
になります。
EAは 関数分割が基本です。
② インジケーターを毎ティック作る
初心者がよくやるミスです。
void OnTick()
{
int handle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);
}
このコードは ティックごとにインジケーターを作成します。
結果
になります。
正しくは OnInitで作成します。
よくある失敗
無限注文EA
次のコードは初心者がよく作る危険なEAです。
void OnTick()
{
if(signal)
{
trade.Buy(0.1);
}
}
このコードは
条件がtrueの間、ティックごとに注文します。
結果
という事故になります。
対策
が必要です。
5. OnTickで絶対に覚えるべき実装テクニック(新バー判定・処理制御)
5.1 なぜOnTickに制御ロジックが必要なのか
OnTickは ティック(価格更新)ごとに実行されるイベント関数です。
そのため、何も制御しない場合、EAは 非常に高頻度で同じ処理を繰り返すことになります。
例えば次のようなコードです。
void OnTick()
{
if(signal)
{
trade.Buy(0.1);
}
}
このコードは条件が成立している間、
注文を出し続ける可能性があります。
結果として
といった重大な問題が発生します。
この問題を防ぐために、EAでは次のような制御を行います。
特に 新バー判定 はほぼすべてのEAで使用される基本テクニックです。
5.2 新バー判定(最も重要なテクニック)
新バー判定とは
ローソク足が更新されたタイミングで処理を実行する方法
です。
これにより
- ティックごとの処理を防ぐ
- バックテストの安定
- EAの負荷軽減
が可能になります。
基本コードは次の通りです。
bool IsNewBar()
{
static datetime lastBarTime = 0;
datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
if(currentBarTime != lastBarTime)
{
lastBarTime = currentBarTime;
return true;
}
return false;
}
OnTickでは次のように使用します。
void OnTick()
{
if(!IsNewBar())
return;
Print("New bar detected");
}
このコードの動作
- 新しいローソク足が生成されたときだけ処理
- それ以外のティックでは処理をスキップ
結果として
EAの処理は1バーに1回だけ実行されます。
5.3 ポジション確認(重複注文防止)
EAでは 既存ポジション確認も重要です。
次のように書くと安全です。
void OnTick()
{
if(PositionSelect(_Symbol))
return;
if(signal)
{
trade.Buy(0.1);
}
}
このコードの意味
つまり 重複エントリー防止です。
EAでは非常によく使われるパターンです。
5.4 フラグ管理(エントリー回数制御)
もう一つの重要テクニックが フラグ管理です。
例
bool traded = false;
void OnTick()
{
if(traded)
return;
if(signal)
{
trade.Buy(0.1);
traded = true;
}
}
このコードでは
という制御になります。
EAでは
などの制御に使われます。
つまずきポイント
① 新バー判定を書かない
初心者EAの多くは
ティックごとに売買判断
をしています。
その結果
- バックテストが不安定
- スプレッド影響増加
- 約定数過多
になります。
多くのEAは バー単位ロジックで設計されています。
② iTimeの使い方を間違える
新バー判定では
iTime(_Symbol, PERIOD_CURRENT, 0)
を使います。
意味
| 引数 |
内容 |
| Symbol |
通貨ペア |
| Timeframe |
時間足 |
| 0 |
最新バー |
この理解がないと、誤動作するEAになります。
よくある失敗
バックテストと実運用のズレ
ティックEAの場合
の影響を受けます。
その結果
というケースが発生します。
この問題を減らすために
バー単位ロジック
が多くのEAで採用されています。
6. OnTickのパフォーマンス最適化(EAを高速化する方法)
6.1 なぜOnTickの最適化が重要なのか
OnTickは ティック(価格更新)ごとに実行される関数です。
そのため、EAのパフォーマンスは OnTick内部の処理効率に大きく依存します。
例えば流動性の高い通貨ペアでは、1秒間に次のような回数でティックが発生することがあります。
| 市場状況 |
ティック数(目安) |
| 通常市場 |
1秒に数回 |
| ロンドン市場 |
1秒に10回以上 |
| ニュース発表 |
1秒に数十回 |
もしOnTickに重い処理を書いてしまうと
- EAが遅くなる
- バックテストが極端に遅くなる
- VPSのCPU使用率が上がる
といった問題が発生します。
そのためEA開発では OnTickをできるだけ軽量にする設計が重要です。
6.2 不要な処理を減らす(早期リターン)
最も基本的な最適化テクニックが 早期リターン(Early Return) です。
不要な条件の場合は すぐに処理を終了します。
例
void OnTick()
{
if(!IsNewBar())
return;
CheckSignal();
}
このコードの意味
結果として
になります。
この方法は ほぼすべてのEAで使われる基本テクニックです。
6.3 インジケーターはOnInitで作成する
初心者がよくやるミスが
OnTick内でインジケーターを作成することです。
誤った例
void OnTick()
{
int ma = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);
}
このコードは ティックごとにインジケーターを生成します。
問題
正しい方法は OnInitで作成することです。
int maHandle;
int OnInit()
{
maHandle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);
return(INIT_SUCCEEDED);
}
そしてOnTickでは値だけ取得します。
void OnTick()
{
double buffer[];
CopyBuffer(maHandle,0,0,1,buffer);
}
この設計は EA開発の基本パターンです。
6.4 不要なログ出力を減らす
Print() はデバッグには便利ですが、
大量に使うと ログ処理がボトルネックになります。
例
void OnTick()
{
Print("Tick received");
}
ティックが多い通貨では
が出力されます。
その結果
が発生することがあります。
対策
例
if(signal)
{
Print("Entry signal");
}
6.5 ループ処理を最小化する
OnTick内で大きなループを書くと、
ティック頻度によっては EAが極端に遅くなることがあります。
例(非推奨)
for(int i=0;i<10000;i++)
{
// heavy calculation
}
このような処理は
などへ移動する方が安全です。
つまずきポイント
① ティックEAはCPU負荷が高い
ティックベースEAは
になりやすいです。
そのため
が重要になります。
② バックテスト速度が極端に遅い
OnTick処理が重いと
になることがあります。
原因の多くは
です。
よくある失敗
インジケーターを毎ティック作る
これは初心者EAで最も多いミスです。
結果
になります。
EAでは必ず
OnInitでインジケーター作成
という設計にしましょう。
7. OnTickを使う際の注意点(EA開発で起きやすいトラブル)
7.1 同一条件での連続エントリー
OnTickを使うEAで最も多いトラブルは 同じ条件で何度も注文してしまう問題です。
例えば次のコードです。
void OnTick()
{
if(signal)
{
trade.Buy(0.1);
}
}
このコードでは、条件が成立している限り ティックごとに注文します。
例えば次の状況を考えます。
| 時刻 |
状態 |
| 10:00:01 |
条件成立 |
| 10:00:01 |
ティック |
| 10:00:01 |
注文 |
| 10:00:01 |
次ティック |
| 10:00:01 |
再注文 |
この結果
という事故が起きることがあります。
対策としては次の方法を使います。
例
void OnTick()
{
if(PositionSelect(_Symbol))
return;
if(signal)
{
trade.Buy(0.1);
}
}
これにより 既存ポジションがある場合は新規注文しない設計になります。
7.2 ティックが来ないとEAは動かない
OnTickは 価格更新イベントで動く関数です。
そのため次の状況では EAが実行されません。
- 市場休場(週末)
- 流動性の低い銘柄
- データ停止
- チャート更新停止
初心者がよく
「EAが止まっている」
と感じるケースの多くは ティックが来ていないだけです。
もし一定時間ごとに処理したい場合は OnTimerイベントを使います。
例
EventSetTimer(60);
これにより 60秒ごとにOnTimerが実行されます。
7.3 バックテストと実運用の違い
OnTickベースEAでは
で挙動が変わることがあります。
理由は次の通りです。
| 要因 |
説明 |
| ティック生成 |
テストでは疑似ティック |
| 約定速度 |
実口座は遅延あり |
| スプレッド |
ブローカー差 |
| 流動性 |
市場状況 |
そのため
というケースがあります。
特に
では影響が大きくなります。
7.4 VPS環境の影響
EAは通常 VPS(仮想サーバー)で動かします。
VPS環境によって
が変わります。
OnTickは高頻度処理なので
では処理遅延が起きることがあります。
EA運用では
が重要です。
つまずきポイント
① OnTickが動いているか確認しない
EAが動いているか確認するには
Print("Tick");
などでログ確認すると分かります。
② デモとリアルの違い
デモ口座では
がリアルと異なる場合があります。
EA検証では
が推奨されます。
よくある失敗
ティックEAを理解せずに設計する
初心者が作るEAの多くは
を考慮していません。
その結果
になります。
EA設計では
を組み合わせることが重要です。
8. FAQ(よくある質問)
8.1 OnTickとは何ですか?
OnTickは、価格のティック(Tick:価格更新)が発生したときに自動実行されるMQL5のイベント関数です。
EA(Expert Advisor)はイベント駆動型のプログラムであり、市場から新しい価格が届くとOnTickが呼び出されます。
多くのEAでは、この関数の中で
などを行います。
8.2 OnTickはどのくらいの頻度で実行されますか?
OnTickの実行頻度は 市場のティック頻度に依存します。
例えば
| 市場状況 |
ティック頻度 |
| 通常市場 |
1秒に数回 |
| ロンドン市場 |
1秒に10回以上 |
| ニュース発表時 |
1秒に数十回 |
ただし、流動性が低い時間帯では 数秒〜数十秒OnTickが呼ばれないこともあります。
つまり、OnTickは
時間ではなく価格更新に反応するイベント
です。
8.3 OnTickとOnTimerの違いは何ですか?
両者の違いは 実行トリガーです。
| 関数 |
実行タイミング |
| OnTick |
価格更新時 |
| OnTimer |
指定時間ごと |
OnTickは市場イベントに反応する関数であり、OnTimerは 一定時間ごとに処理したい場合に使います。
例えば
などではOnTimerが使われることがあります。
8.4 OnTickはインジケーターでも使えますか?
使えません。
OnTickは EA専用のイベント関数です。
インジケーターでは通常
という関数が使用されます。
8.5 OnTickは複数定義できますか?
できません。
EAの中でOnTickは 1つだけ定義できます。
次のようなコードはコンパイルエラーになります。
void OnTick()
{
}
void OnTick()
{
}
8.6 OnTickに重い処理を書くとどうなりますか?
ティックは高頻度で発生するため、OnTickに重い処理を書くと
- EAが遅くなる
- バックテストが極端に遅くなる
- CPU負荷が増える
といった問題が発生します。
そのためEAでは
などの最適化を行います。
8.7 OnTickが動かない場合の原因は何ですか?
OnTickが動かない場合、次の原因が考えられます。
- 市場が閉まっている(週末)
- ティックが発生していない
- EAが停止している
- 自動売買が無効
- チャートが更新されていない
最も多い原因は ティックが来ていないことです。
8.8 OnTickだけでEAを作れますか?
基本的なEAは OnTickだけでも作成可能です。
ただし実際のEAでは次の関数を併用することが多いです。
OnInit()(初期化)
OnTick()(売買ロジック)
OnDeinit()(終了処理)
この構造が EAの基本テンプレートになります。