- 1 1. mql5 itime-multitimeframeとは何か
- 2 2. itimeの基本的な使い方
- 3 3. itimeを使ったマルチタイムフレーム(MTF)の実装方法
- 4 4. バックテストでズレる原因と対策(MTFの落とし穴)
- 5 5. itime × 他関数の組み合わせ(実務で使う応用テクニック)
- 6 6. itimeを使ったEA実装例(エントリーまでの完全サンプル)
- 7 7. FAQ(よくある質問と解決方針)
1. mql5 itime-multitimeframeとは何か
MQL5における「itime-multitimeframe」とは、itime関数を使って異なる時間足(タイムフレーム)のバー時間を取得し、複数時間軸を組み合わせて処理する技術を指します。
結論から言うと、
「異なる時間足のバーの開始時刻を正しく取得し、ロジックの基準として使う」ことが目的です。
特にEA(自動売買)やインジケーターでは、
- 上位足(例:H1)のトレンドを見ながら
- 下位足(例:M5)でエントリーする
といった処理が一般的であり、その基盤となるのがitimeです。
1.1 itime関数の基本仕様
itimeは、指定した条件のバーの「開始時刻」を取得する関数です。
datetime time = iTime(_Symbol, PERIOD_H1, 0);
各引数の意味
_Symbol:通貨ペア(現在チャート)PERIOD_H1:時間足(ここでは1時間足)0:バー位置(0 = 最新バー)
戻り値
datetime型(Unix時間形式の時刻データ)
この値はそのままでは見づらいため、通常は以下のように変換します。
Print(TimeToString(time));
重要ポイント(初心者がつまずく箇所)
- itimeは「価格」ではなく「時間」を返す
- shift(バー位置)の意味を誤解しやすい
0→ 最新バー1→ 1本前のバー
1.2 マルチタイムフレーム(MTF)とは
マルチタイムフレーム(MTF)とは、
現在のチャートとは異なる時間足のデータを同時に扱う手法です。
例えば:
| 現在のチャート | 参照する時間足 | 目的 |
|---|---|---|
| M5 | H1 | 上位トレンド確認 |
| M1 | M15 | ノイズ除去 |
| H1 | D1 | 長期方向性 |
このように、複数の時間軸を組み合わせることで、
より安定したトレード判断が可能になります。
なぜMTFが重要なのか
- 単一時間足ではノイズが多い
- 上位足の方向に従うことで勝率が安定しやすい
- EAのロジック精度が向上する
よくある誤解
- 「時間足を変えれば同じデータが見える」
→ 誤り(バー構造が異なるため別物)
1.3 なぜitimeでMTFが重要なのか
MTFで最も重要なのは、
**「異なる時間足のバーを正しく対応付けること」**です。
ここでitimeが必要になります。
問題:時間のズレ
例えば:
- M5の現在バー(0)
- H1の現在バー(0)
これらは同じタイミングとは限りません。
解決方法:itimeで時間を基準にする
datetime h1_time = iTime(_Symbol, PERIOD_H1, 0);
datetime m5_time = iTime(_Symbol, PERIOD_M5, 0);
このように取得した時間を比較することで:
- 上位足が更新されたか
- 現在のバーがどの上位足に属するか
を判定できます。
実務での使い道
- 上位足の「確定」を検知
- 新しいトレンドの開始判定
- エントリータイミングの同期
よくある失敗(重要)
- 時間ではなくshiftで合わせようとする
→ 異なる時間足では無意味 - itimeの値を比較せずにロジックを組む
→ MTFでズレが発生し、誤動作 - データ未ロードで0が返る
→ 初回実行時に発生しやすい
実務的な理解(重要)
itimeは単なる関数ではなく、
「時間同期の基準(タイムスタンプ管理)」の役割を持つと考えると理解が早くなります。
2. itimeの基本的な使い方
itime関数はシンプルですが、引数の意味と使い方を正しく理解しないと誤動作の原因になります。
ここでは、初心者でもそのまま使える形で解説します。
2.1 基本構文
itimeの基本形は以下です。
datetime time = iTime(_Symbol, PERIOD_H1, 0);
この1行で、指定した時間足の最新バーの開始時刻を取得できます。
最小実行例(動作確認)
void OnTick()
{
datetime time = iTime(_Symbol, PERIOD_H1, 0);
Print(TimeToString(time));
}
このコードを実行すると、ログにH1の現在バーの時刻が表示されます。
実務でのポイント
- OnTick内で呼び出すのが基本
- ログで確認しながら開発するのが安全
2.2 引数の意味(重要)
itimeは3つの引数で構成されています。
iTime(symbol, timeframe, shift)
① symbol(通貨ペア)
_Symbol
- 現在のチャートの通貨ペア
- 他シンボルを指定することも可能
iTime("EURUSD", PERIOD_H1, 0);
② timeframe(時間足)
代表例:
PERIOD_M1(1分足)PERIOD_M5(5分足)PERIOD_H1(1時間足)PERIOD_D1(日足)
③ shift(バー位置)
ここが最重要です。
| shift | 意味 |
|---|---|
| 0 | 最新バー |
| 1 | 1本前 |
| 2 | 2本前 |
つまずきポイント(超重要)
- 0は「確定バー」ではない
→ まだ形成中のバー - 確定バーを使うなら:
iTime(_Symbol, PERIOD_H1, 1);
2.3 戻り値の扱い
itimeの戻り値は datetime型 です。
そのままだと扱いづらいため、通常は文字列に変換します。
datetime time = iTime(_Symbol, PERIOD_H1, 0);
string str = TimeToString(time);
Print(str);
フォーマット指定
TimeToString(time, TIME_DATE | TIME_MINUTES);
実務での使い方(比較)
static datetime last_time = 0;
datetime current_time = iTime(_Symbol, PERIOD_H1, 0);
if(current_time != last_time)
{
Print("新しいH1バーが開始");
last_time = current_time;
}
2.4 よくある失敗と注意点
① データ未取得で0になる
datetime time = iTime(_Symbol, PERIOD_H1, 0);
→ 0 が返る場合:
- ヒストリーデータ未ロード
- 初回起動時
対策:
if(time == 0)
{
Print("データ未取得");
}
② OnTickで毎回呼びすぎる
- 無駄な負荷
- パフォーマンス低下
対策:
- 必要なタイミングのみ取得
- static変数で管理
③ shiftの誤用
よくあるミス:
iTime(_Symbol, PERIOD_H1, 0); // 確定バーと思い込む
→ 実際は未確定
④ 時間の比較ミス
NG例:
if(iTime(...) == TimeCurrent())
→ 比較対象が違う(バー時間 vs 現在時刻)
2.5 実務での最小テンプレ(推奨)
static datetime last_h1_time = 0;
void OnTick()
{
datetime current_h1_time = iTime(_Symbol, PERIOD_H1, 0);
if(current_h1_time == 0) return;
if(current_h1_time != last_h1_time)
{
Print("H1更新");
last_h1_time = current_h1_time;
}
}
このコードの役割
- 上位足更新検知
- MTFロジックの基礎
実務視点(重要)
このパターンは:
- トレード実行タイミング制御
- ロジックの安定化
に直結します。
3. itimeを使ったマルチタイムフレーム(MTF)の実装方法
ここでは、実務でそのまま使えるMTF実装パターンを解説します。
単なる関数の使い方ではなく、ズレを防ぐための設計が本質です。
3.1 上位足のバー更新を検知する
MTFの基本は、上位足の更新タイミングを正確に検知することです。
実装コード(最重要パターン)
static datetime last_h1_time = 0;
void OnTick()
{
datetime current_h1_time = iTime(_Symbol, PERIOD_H1, 0);
if(current_h1_time == 0) return;
if(current_h1_time != last_h1_time)
{
Print("H1の新しいバーが開始");
// ここにロジックを書く
last_h1_time = current_h1_time;
}
}
何をしているのか
- H1バーの開始時刻を取得
- 前回と比較
- 違えば「新しいバー」と判断
実務的メリット
- 無駄なエントリー防止
- ロジックの再現性向上
- バックテストと実運用の乖離減少
よくある失敗
OnTickごとにロジックを走らせる
→ 過剰エントリーの原因
3.2 下位足と上位足を同期させる
MTFで最も重要なのは、
「現在の下位足がどの上位足に属するか」を正しく把握することです。
基本アイデア
datetime h1_time = iTime(_Symbol, PERIOD_H1, 0);
datetime m5_time = iTime(_Symbol, PERIOD_M5, 0);
この2つを比較します。
実用コード例
datetime h1_time = iTime(_Symbol, PERIOD_H1, 0);
datetime h1_prev = iTime(_Symbol, PERIOD_H1, 1);
datetime m5_time = iTime(_Symbol, PERIOD_M5, 0);
if(m5_time >= h1_time)
{
Print("現在のM5は最新H1バーに属する");
}
なぜこれが必要か
- shiftでは時間足間の対応は取れない
- 時間(datetime)で合わせる必要がある
重要な理解
- M5はH1の中に複数存在する
- つまり「包含関係」で管理する
3.3 上位足確定タイミングで処理する
トレードロジックでは、
「確定した上位足」を使うのが基本です。
NG例(未確定バー使用)
iTime(_Symbol, PERIOD_H1, 0);
OK例(確定バー)
iTime(_Symbol, PERIOD_H1, 1);
実務コード例
datetime h1_confirmed = iTime(_Symbol, PERIOD_H1, 1);
static datetime last_h1_confirmed = 0;
if(h1_confirmed != last_h1_confirmed)
{
Print("H1確定バー更新");
// 確定データで判断
last_h1_confirmed = h1_confirmed;
}
なぜ重要か
- 未確定バーは値が変わる
- バックテストとの不一致原因になる
3.4 MTFロジックの実用テンプレ
ここまでを組み合わせた、実戦用テンプレートです。
static datetime last_h1_time = 0;
void OnTick()
{
datetime h1_time = iTime(_Symbol, PERIOD_H1, 0);
datetime h1_confirmed = iTime(_Symbol, PERIOD_H1, 1);
if(h1_time == 0 || h1_confirmed == 0) return;
// H1更新検知
if(h1_time != last_h1_time)
{
Print("新しいH1開始");
// 確定バーでロジック実行
Print("確定H1時間: ", TimeToString(h1_confirmed));
last_h1_time = h1_time;
}
}
このテンプレの役割
- 上位足更新検知
- 確定データ使用
- 再現性確保
3.5 よくある失敗と注意点(実務レベル)
① 時間足ごとのズレを無視
- H1とM5は同じindexではない
→ shift依存は危険
② 未確定バーでエントリー
- リペイント的挙動になる
→ 実運用で崩壊
③ 初回ロード問題
- iTimeが0を返す
→ チェック必須
④ マルチシンボル時の遅延
iTime("EURUSD", PERIOD_H1, 0);
→ データ未取得の可能性
3.6 実務視点のまとめ
MTFにおけるitimeの役割は:
- 時間同期の基準
- ロジック発火トリガー
- 再現性確保の核心
設計の本質
- shiftではなく時間で管理
- 未確定データを使わない
- 更新タイミングを制御
4. バックテストでズレる原因と対策(MTFの落とし穴)
MTF(マルチタイムフレーム)を使ったEAで最も多い問題が、
**「バックテストでは勝っているのに、実運用で崩れる」**という現象です。
結論として、その主因の多くは
**itimeの使い方(=時間同期のミス)**にあります。
4.1 バックテストと実運用がズレる理由
ズレの原因は主に以下の3つです。
① 未確定バーを使用している
iTime(_Symbol, PERIOD_H1, 0);
このコードは、**形成中のバー(未確定)**を参照します。
なぜ問題か
- バックテスト → 確定データで処理される
- 実運用 → 値が変動する
→ 結果として「未来を見ていた」状態になる
対策
iTime(_Symbol, PERIOD_H1, 1);
必ず確定バーを使う
4.2 ティック再現性の問題
バックテストでは:
- ティックは疑似生成(モデル化)
実運用では:
- リアルティック(不規則)
問題の本質
if(条件)
{
エントリー();
}
この「条件」が:
- ティック単位で変わる
- 実運用では揺れる
対策
- バー単位で判定する
- 上位足更新タイミングのみ処理
実装例
static datetime last_h1_time = 0;
datetime current_h1_time = iTime(_Symbol, PERIOD_H1, 0);
if(current_h1_time != last_h1_time)
{
// バー確定単位で判断
last_h1_time = current_h1_time;
}
4.3 時間同期ミス(MTF最大の罠)
最も多い致命的なミスです。
NG例(shift依存)
double h1_close = iClose(_Symbol, PERIOD_H1, 0);
double m5_close = iClose(_Symbol, PERIOD_M5, 0);
→ 同じタイミングではない
問題
- H1の0バー ≠ M5の0バー
- 時間的にズレている
正しい考え方
- 時間で一致させる
改善例
datetime h1_time = iTime(_Symbol, PERIOD_H1, 0);
datetime m5_time = iTime(_Symbol, PERIOD_M5, 0);
if(m5_time >= h1_time)
{
// 同一H1内のM5
}
4.4 ヒストリーデータ不足問題
datetime time = iTime(_Symbol, PERIOD_H1, 0);
→ 0が返るケース
原因
- データ未ロード
- 初回起動
- 他シンボル参照
対策
if(time == 0)
{
return;
}
実務での注意
- Strategy Testerでは発生しにくい
- 本番環境で頻発する
4.5 マルチシンボル×MTFの罠
iTime("EURUSD", PERIOD_H1, 0);
問題
- 対象シンボルのデータが無い
- 遅延・NULL値
対策
SymbolSelect("EURUSD", true);
さらに重要
- 全シンボルのデータ同期は保証されない
- EAの再現性が落ちる
4.6 実務での安定設計(重要)
MTF EAを安定させるには、以下が必須です。
設計原則
① 確定バーのみ使用
② 時間で同期(shift禁止)
③ バー更新時のみ処理
④ データ未取得チェック必須
推奨テンプレ
static datetime last_h1_time = 0;
void OnTick()
{
datetime h1_time = iTime(_Symbol, PERIOD_H1, 0);
datetime h1_confirmed = iTime(_Symbol, PERIOD_H1, 1);
if(h1_time == 0 || h1_confirmed == 0) return;
if(h1_time != last_h1_time)
{
// 確定データでロジック
last_h1_time = h1_time;
}
}
4.7 よくある失敗まとめ
① バックテストだけ最適化
→ 実運用で崩壊
② ティック依存ロジック
→ 再現性が低い
③ MTFなのに時間を見ていない
→ 根本的に破綻
④ 未確定バー使用
→ 過剰最適化(未来参照)
4.8 実務視点の結論
MTFで勝てるかどうかは、
ロジックよりも 「時間管理の精度」 に依存します。
本質
- itimeは単なる関数ではない
- 時間同期エンジンの核
期待値視点
- 正しく実装 → 再現性↑ → PF安定
- ミスあり → ランダム性↑ → 崩壊
5. itime × 他関数の組み合わせ(実務で使う応用テクニック)
MTFを実務レベルで扱うには、itime単体では不十分です。
「時間(itime)」を軸に、他の関数と組み合わせて使うことが本質になります。
ここでは、実際のEA開発で頻出する組み合わせを解説します。
5.1 itime × iBarShift(時間→インデックス変換)
最重要パターンです。
目的
「指定した時間に対応するバー位置(shift)を取得する」
基本コード
datetime h1_time = iTime(_Symbol, PERIOD_H1, 0);
int shift = iBarShift(_Symbol, PERIOD_M5, h1_time);
何をしているか
- H1のバー時間を取得
- その時間に対応するM5のバー位置を取得
実務用途
- 上位足→下位足の位置特定
- 同期した価格取得
- シグナル整合性確保
重要ポイント
iBarShiftは「時間ベース」で検索- shiftのズレ問題を解決できる
よくある失敗
iBarShiftの戻り値が-1
→ 対応バーなし(データ不足)
対策
if(shift < 0)
{
Print("対応バーなし");
return;
}
5.2 itime × iClose / iOpen(時間同期価格取得)
NGパターン
double h1_close = iClose(_Symbol, PERIOD_H1, 0);
double m5_close = iClose(_Symbol, PERIOD_M5, 0);
→ 時間が一致していない
正しい方法
datetime h1_time = iTime(_Symbol, PERIOD_H1, 0);
int shift = iBarShift(_Symbol, PERIOD_M5, h1_time);
double m5_price = iClose(_Symbol, PERIOD_M5, shift);
これで何ができるか
- 同一時間軸での価格比較
- 上位足と下位足の整合性確保
実務メリット
- シグナルの一貫性向上
- 誤判定の削減
5.3 itime × CopyRates(高速データ取得)
大量データを扱う場合は、CopyRatesを使います。
基本コード
MqlRates rates[];
int copied = CopyRates(_Symbol, PERIOD_H1, 0, 100, rates);
itimeとの組み合わせ
datetime target_time = iTime(_Symbol, PERIOD_H1, 1);
for(int i=0; i<copied; i++)
{
if(rates[i].time == target_time)
{
Print("一致バー発見");
}
}
実務用途
- バックテスト用ロジック
- 複雑な条件判定
- 複数バー参照
注意点
- 配列は時系列順(古い→新しい or 逆)に注意
- インデックス方向を誤るとバグ
5.4 itime × TimeCurrent(リアル時間との比較)
使用例
datetime bar_time = iTime(_Symbol, PERIOD_H1, 0);
datetime now = TimeCurrent();
注意
if(bar_time == now)
→ 基本的に成立しない
正しい使い方
if(now >= bar_time)
{
// 現在はこのバーの時間帯
}
実務用途
- セッション管理
- 時間帯フィルター
- トレード時間制御
5.5 itime × 複数時間足(MTF拡張)
例:H1+M15+M5
datetime h1 = iTime(_Symbol, PERIOD_H1, 0);
datetime m15 = iTime(_Symbol, PERIOD_M15, 0);
datetime m5 = iTime(_Symbol, PERIOD_M5, 0);
実務ロジック例
if(m5 >= m15 && m15 >= h1)
{
Print("全時間足が同一トレンド内");
}
何をしているか
- 包含関係チェック
- 時間整合性確認
注意点
- 時間足が増えるほどズレリスク増大
- 必ず時間ベースで管理する
5.6 実務テンプレ(応用版)
static datetime last_h1_time = 0;
void OnTick()
{
datetime h1_time = iTime(_Symbol, PERIOD_H1, 0);
if(h1_time == 0) return;
if(h1_time != last_h1_time)
{
int m5_shift = iBarShift(_Symbol, PERIOD_M5, h1_time);
if(m5_shift < 0) return;
double price = iClose(_Symbol, PERIOD_M5, m5_shift);
Print("同期価格: ", price);
last_h1_time = h1_time;
}
}
5.7 よくある失敗まとめ(応用編)
① iBarShiftを使わない
→ 時間ズレ発生
② 配列インデックスの誤認
→ CopyRatesで多発
③ マルチ時間足でshift依存
→ ロジック崩壊
④ 時間比較を軽視
→ 再現性消失
5.8 実務視点の結論
itime単体ではなく:
- iBarShift → 位置特定
- CopyRates → データ取得
- iClose等 → 価格参照
これらを組み合わせて初めて、
実運用に耐えるMTFロジックになります。
本質まとめ
- itime = 時間軸
- iBarShift = 座標変換
- CopyRates = データ取得
6. itimeを使ったEA実装例(エントリーまでの完全サンプル)
ここでは、これまで解説した内容を統合し、
実際にエントリーまで行うMTF EAの最小構成を提示します。
目的は、
**「再現性のあるMTFロジックをそのまま使える形で理解すること」**です。
6.1 ロジック設計(シンプルかつ実務寄り)
今回の例では以下の条件を使います。
トレード条件
- 上位足(H1)の確定バーが陽線 → 買い
- 上位足(H1)の確定バーが陰線 → 売り
- 下位足(M5)でエントリー
設計意図
- 確定バーのみ使用 → 再現性確保
- MTF同期 → ズレ防止
- バー更新時のみ実行 → 過剰エントリー防止
6.2 完全コード(コピペ可)
#include <Trade/Trade.mqh>
CTrade trade;
static datetime last_h1_time = 0;
void OnTick()
{
// 上位足(H1)
datetime h1_time = iTime(_Symbol, PERIOD_H1, 0);
datetime h1_confirmed = iTime(_Symbol, PERIOD_H1, 1);
if(h1_time == 0 || h1_confirmed == 0) return;
// 新しいH1バー検知
if(h1_time != last_h1_time)
{
last_h1_time = h1_time;
// H1確定バーの価格取得
double open = iOpen(_Symbol, PERIOD_H1, 1);
double close = iClose(_Symbol, PERIOD_H1, 1);
// M5側の対応バー取得
int m5_shift = iBarShift(_Symbol, PERIOD_M5, h1_time);
if(m5_shift < 0) return;
double m5_price = iClose(_Symbol, PERIOD_M5, m5_shift);
// エントリー条件
if(close > open)
{
Print("BUY条件成立");
trade.Buy(0.1);
}
else if(close < open)
{
Print("SELL条件成立");
trade.Sell(0.1);
}
}
}
6.3 コードの分解解説(重要ポイントのみ)
① 上位足更新検知
if(h1_time != last_h1_time)
→ 処理を1時間に1回に制限
② 確定バーの使用
iClose(_Symbol, PERIOD_H1, 1);
→ 未確定データ排除
③ MTF同期
int m5_shift = iBarShift(_Symbol, PERIOD_M5, h1_time);
→ 時間ベースで位置取得
④ エントリー
trade.Buy(0.1);
→ 最小ロジック(実務ではリスク管理追加)
6.4 よくある失敗(実務レベル)
① ポジション管理をしない
- 毎回エントリー
→ 無限ポジション
対策
if(PositionSelect(_Symbol)) return;
② スプレッド無視
→ エントリー精度低下
③ ロット固定
→ リスク管理不備
④ iBarShift未チェック
→ -1でクラッシュ
6.5 実務用に拡張するポイント
必須追加要素
- ロット計算(リスク%)
- SL / TP設定
- スプレッドフィルター
- 時間帯制御
- 最大ポジション制限
例(簡易)
if(SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) > 20) return;
6.6 実務視点の評価
このロジックの特徴
- 再現性:高い
- シンプル:高い
- エッジ:低い(そのままでは勝てない)
期待値観点
- ベースとしては有効
- シグナル部分を強化すれば実用化可能
6.7 本質まとめ
このEAの本質はロジックではなく:
- 時間同期
- 確定データ使用
- 更新トリガー制御
重要認識
勝てるEAは:
- 指標が優秀
ではなく - 時間処理が正確
6.8 次にやるべきこと
- フィルター追加(トレンド / ボラティリティ)
- リスク管理導入
- 最適化(ただし過剰最適化はNG)
7. FAQ(よくある質問と解決方針)
Q1. itimeが0を返すのはなぜですか?
回答方針:データ未取得が主因。初期化・履歴ロードを確認する。
- 初回起動時や未ロード時に発生
- 他シンボル・他時間足で起きやすい
対策:
if(iTime(_Symbol, PERIOD_H1, 0) == 0) return;
Q2. shift=0は確定バーですか?
回答方針:未確定バー。確定はshift=1を使う。
0→ 形成中1→ 確定済み
対策:
iTime(_Symbol, PERIOD_H1, 1);
Q3. 異なる時間足でshiftを合わせれば同期できますか?
回答方針:不可能。時間(datetime)で合わせる必要がある。
- H1のshift=0 ≠ M5のshift=0
対策:
datetime t = iTime(_Symbol, PERIOD_H1, 0);
int shift = iBarShift(_Symbol, PERIOD_M5, t);
Q4. バックテストでは勝つのに実運用で負ける理由は?
回答方針:未確定バー・時間ズレ・ティック差が主因。
主な原因:
- 未確定バー使用
- ティック依存
- MTF同期ミス
対策:
- 確定バーのみ使用
- バー単位で処理
- 時間比較で同期
Q5. iBarShiftが-1になるのはなぜですか?
回答方針:対応する時間のバーが存在しないため。
原因:
- データ不足
- シンボル未選択
- 時間ズレ
対策:
if(shift < 0) return;
Q6. itimeとTimeCurrentは同じですか?
回答方針:異なる。用途も完全に別。
| 関数 | 意味 |
|---|---|
| itime | バーの開始時刻 |
| TimeCurrent | 現在のサーバー時刻 |
注意:
// NG
if(iTime(...) == TimeCurrent())
Q7. OnTickで毎回itimeを呼んでも問題ないですか?
回答方針:動くが非効率。更新検知で制御すべき。
問題:
- 無駄な処理増加
- エントリー乱発
対策:
static datetime last;
if(current != last)
Q8. マルチシンボルでitimeを使う際の注意点は?
回答方針:データ未取得と同期ズレに注意。
問題:
- シンボルごとにデータ状態が異なる
- 遅延・0値発生
対策:
SymbolSelect("EURUSD", true);
FAQまとめ(実務視点)
- itimeは「時間管理の核」
- MTFは「時間同期の精度」で決まる
- バグの9割は「時間の扱いミス」
最終結論
- shiftではなく時間で考える
- 未確定データは使わない
- 更新タイミングで処理する