ランダムウォークへの挑戦⑬ | 零号機に「記憶」を与える ― mql4でエントリーから決済までの相場環境を記録する(2026/8/2)

ランダムウォーク 未分類

はじめに

前回からChapter2「学習」に入りました。

Chapter1「観測」では、約11年半のバックテスト結果をPythonで分析し、

  • 月別損益
  • エントリー・決済時間帯
  • エントリー・決済曜日
  • 保有時間
  • 連勝・連敗
  • ドローダウン

など、さまざまな角度から零号機の特徴を調べてきました。

その結果、時間帯や保有時間などによって成績に差があることが分かりました。

ランダムウォークへの挑戦⑫ | Chapter2「学習」始動 ー零号機は何を学ぶべきなのかー(2026/8/2)
はじめに前回までのChapter1「観測」では、Pythonを使って約11年半・1,720回の取引をさまざまな角度から分析しました。月別損益、時間帯、曜日、保有時間、連勝・連敗、ドローダウン。一つひとつ分析していくことで、バックテストの最終…

しかし、Chapter1で分かったのは、

「何が起きていたのか」

までです。

例えば、4~24時間保有した取引の成績が悪かったとしても、

なぜ、その取引は長時間保有することになり、最終的に負けたのか

までは分かりません。

エントリー時から相場の値動きが小さかったのか。

エントリー後にボラティリティが低下したのか。

あるいは、ボリンジャーバンドの状態が変化したのか。

原因を調べるためには、取引結果だけでなく、取引を開始したときと終了したときの相場環境も必要になります。

そこで今回はMQL4を改修し、

「どのような相場でエントリーし、どのような相場で決済したのか」

を記録できるようにします。

零号機に「記憶」を与える作業です。


今回記録する情報

今回の改修では、1回の取引について大きく3種類の情報を残します。

① 取引そのものの情報

ticket
side
entry_time
exit_time
entry_price
exit_price
lots
profit
holding_minutes
band_condition
reverse_condition

これは、

  • BUYかSELLか
  • いつエントリー・決済したか
  • いくらで売買したか
  • 何分保有したか
  • 最終的にいくら勝った・負けたか
  • どの条件で決済したか

といった、取引そのものの記録です。

② エントリー時の相場環境

atr14_entry_pips
bb_width_entry_pips
band_distance_entry_pips
spread_entry_pips
entry_hour
entry_weekday
entry_bar_time

③ 決済時の相場環境

今回はさらに、

atr14_exit_pips
bb_width_exit_pips
band_distance_exit_pips
spread_exit_pips

も記録します。

これによって、

エントリー時ATR
        ↓
   ポジション保有
        ↓
決済時ATR

のように、取引中に相場環境がどう変化したのかも分析できるようになります。


なぜエントリー時と決済時の両方を記録するのか

例えば、4~8時間保有して負けた取引があったとします。

エントリー時と決済時のATRが、

Entry ATR = 15 pips
Exit ATR  = 6 pips

だったとします。

このような取引が多数見つかれば、

長時間保有したから負けた

のではなく、

エントリー後にボラティリティが低下した結果、ポジションが長時間捕まり、最終的に負けた

という別の可能性が見えてきます。

逆に、

Entry ATR = 8 pips
Exit ATR  = 16 pips

という取引が勝ちやすければ、

エントリー後のボラティリティ拡大が零号機に有利

という仮説も立てられます。

Chapter1では、

保有時間 → 損益

という関係までしか見られませんでした。

Chapter2では、

エントリー時の相場
        ↓
相場環境の変化
        ↓
決済時の相場
        ↓
取引結果

まで見られるようにします。


今回作る仕組み

ただし、エントリー時と決済時では情報の保存方法を変えます。

【エントリー】

OrderSend()
   ↓
注文成立
   ↓
ticket取得
   ↓
ATR・BB幅・バンド距離・スプレッド等を取得
   ↓
GlobalVariableへ保存


【ポジション保有】

GlobalVariableに
エントリー時の相場環境を保持


【決済】

OrderClose()
   ↓
決済成功
   ↓
その場で決済時の相場環境を取得
   ↓
GlobalVariableから
エントリー時の相場環境を取得
   ↓
取引結果とまとめる
   ↓
trade_log.csvへ保存
   ↓
GlobalVariableを削除

ここが今回の設計のポイントです。

エントリー時の情報は保存しておかなければ後から失われます。

そのため、GlobalVariableを使います。

一方、決済時の情報は決済した瞬間に取得できるため、GlobalVariableへ保存する必要はありません。


1.取引ごとの「記憶」の名前を作る

まず、GlobalVariableの名前を作る関数を用意します。

string EntryKey(
   int ticket,
   string suffix
)
{
   return(
      IntegerToString(ticket)
      + "_"
      + suffix
   );
}

例えば、

ticket = 259597667
suffix = ATR14_PIPS

なら、

259597667_ATR14_PIPS

という名前になります。

同じticketに対して、

259597667_ATR14_PIPS
259597667_BB_WIDTH_PIPS
259597667_BAND_DISTANCE_PIPS
259597667_SPREAD_PIPS
259597667_ENTRY_HOUR
259597667_ENTRY_WEEKDAY
259597667_ENTRY_BAR_TIME

というGlobalVariableを作ることができます。

つまり、

ticketを取引ごとのIDとして、エントリー時の情報を紐付ける

という仕組みです。


2.エントリー時のATRを取得する

例えばATR14は、

double atr14 =
   iATR(
      _Symbol,
      0,
      14,
      0
   );

で取得します。

ATRは、簡単にいえば最近の値動きの大きさを見るための指標です。

ATRが大きければ値動きの大きな相場、ATRが小さければ比較的値動きの小さな相場と考えられます。

取得したATRは、

GlobalVariableSet(
   EntryKey(
      ticket,
      "ATR14_PIPS"
   ),
   atr14 / PipPoint
);

として保存します。

GlobalVariableSet()がGlobalVariableへ値を保存する関数です。

また、

atr14 / PipPoint

によって、値をpips単位へ変換しています。


3.その他のエントリー時情報も記憶する

同じ方法で、

ATR14_PIPS
BB_WIDTH_PIPS
BAND_DISTANCE_PIPS
SPREAD_PIPS
ENTRY_HOUR
ENTRY_WEEKDAY
ENTRY_BAR_TIME

の7種類を保存します。

例えば、

ATR14_PIPS

なら値動きの大きさ、

BB_WIDTH_PIPS

ならボリンジャーバンドの広がり、

SPREAD_PIPS

ならエントリー時の取引コスト、

といった具合です。

この段階では、

どの情報が本当に零号機の成績に影響しているのかは分かりません。

それを調べるのがChapter2です。


4.なぜGlobalVariableが必要なのか

例えば14時にエントリーして、18時に決済したとします。

14:00 Entry
ATR = 8 pips

      ↓

4時間保有

      ↓

18:00 Exit
ATR = 15 pips

18時にiATR()を実行して取得できるのは、18時時点のATRです。

14時時点のATRではありません。

そのため、

14:00
エントリー時の情報を取得
        ↓
GlobalVariableへ保存
        ↓
18:00
GlobalVariableから取得

という処理が必要になります。

GlobalVariableを、エントリーから決済まで取引の状態を覚えておく一時的な記憶領域として使うわけです。


5.決済時の相場環境は、その場で取得する

一方、決済時のATRなどは保存しておく必要がありません。

決済するタイミングで、

double atr14_exit =
   iATR(
      _Symbol,
      0,
      14,
      0
   );

のように取得できます。

同様に、

BB幅
バンドまでの距離
スプレッド

も決済時に計算します。

そして、

Entry ATR
Exit ATR

Entry BB Width
Exit BB Width

という形でCSVに一緒に保存します。

これによって、後からPythonで、

df["atr_change_pips"] = (
    df["atr14_exit_pips"]
    - df["atr14_entry_pips"]
)

のような分析も可能になります。

正なら、

エントリー後にATRが拡大した

負なら、

エントリー後にATRが縮小した

ことを意味します。


6.決済成功後にログを書く

取引情報は、OrderClose()が成功した後に記録します。

例えば、

if(OrderClose(...))
{
   Write_Trade_Log(
      ticket,
      Buy_Exit_Band_Flag,
      Buy_Exit_Reverse_Flag
   );
}

という流れです。

決済注文を出しても、必ず成功するとは限りません。

そのため、

OrderClose()
    ↓
成功確認
    ↓
Write_Trade_Log()

という順番にすることで、実際に決済された取引だけをCSVへ記録します。


7.エントリー時の「記憶」を取り出す

Write_Trade_Log()では、ticketを使ってエントリー時に保存した情報を取得します。

例えば、

double atr14_entry =
   GlobalVariableGet(
      EntryKey(
         ticket,
         "ATR14_PIPS"
      )
   );

とすれば、そのticketに対応するエントリー時ATRを取得できます。

これを、

ATR
BB幅
バンド距離
スプレッド
時間
曜日
バー時刻

について行います。


8.決済時の相場環境を取得する

同じWrite_Trade_Log()の中で、決済時の相場環境も取得します。

ここでは、

atr14_exit_pips
bb_width_exit_pips
band_distance_exit_pips
spread_exit_pips

を計算します。

つまりWrite_Trade_Log()には、

GlobalVariableから取得したEntry情報
              +
その場で計算したExit情報
              +
MT4の取引結果

が集まることになります。

そして、それらを1行のCSVとして保存します。


9.1取引=CSVの1行にする

trade_log.csvでは、

1回の取引を1行

として保存します。

イメージとしては、

ticket
side
entry_time
exit_time
entry_price
exit_price
lots
profit
holding_minutes
band_condition
reverse_condition
atr14_entry_pips
atr14_exit_pips
bb_width_entry_pips
bb_width_exit_pips
band_distance_entry_pips
band_distance_exit_pips
spread_entry_pips
spread_exit_pips
entry_hour
entry_weekday
entry_bar_time

という構造です。

ここで列名を、

entry
exit

で明確に分けておくのがポイントです。

例えば単に、

ATR14_PIPS

としてしまうと、後から見たときにエントリー時なのか決済時なのか分からなくなります。

そのためCSVでは、

atr14_entry_pips
atr14_exit_pips

のようにしておきます。


10.FileOpen()でCSVを開く

CSVへの書き込みには、

FileOpen()

を使います。

今回の保存先は、

trade_log.csv

です。

基本的な処理は、

FileOpen()
    ↓
FileSeek()
    ↓
FileWrite()
    ↓
FileFlush()
    ↓
FileClose()

となります。


11.FileSeek()で末尾へ移動する

すでにCSVに取引データが存在する場合、新しい取引はその下へ追加します。

取引1
取引2
取引3
     ↑
ここまで記録済み

そこで、

FileSeek()

を使ってファイル末尾へ移動してから、

FileWrite()

を実行します。

すると、

取引1
取引2
取引3
取引4 ← 追加

という形で取引履歴を蓄積できます。


12.FileWrite()で取引を記録する

FileWrite()には、今回記録する項目を順番に渡します。

重要なのは、CSVのヘッダーとFileWrite()の順番を必ず一致させることです。

例えば、

atr14_entry_pips
atr14_exit_pips
bb_width_entry_pips
bb_width_exit_pips

というヘッダーなら、FileWrite()側も同じ順番にします。

ここがずれると、

ATRの列にBB幅が入っている

といった非常に厄介なデータになってしまいます。

今後Pythonで分析するデータなので、ここは特に注意します。


13.書き込みが終わったら記憶を削除する

CSVへの保存が完了すれば、その取引についてGlobalVariableへ保存していた情報は不要です。

そこで、

void DeleteEntryState(
   int ticket
)
{
   string suffixes[7] =
   {
      "ATR14_PIPS",
      "BB_WIDTH_PIPS",
      "BAND_DISTANCE_PIPS",
      "SPREAD_PIPS",
      "ENTRY_HOUR",
      "ENTRY_WEEKDAY",
      "ENTRY_BAR_TIME"
   };

   for(
      int i = 0;
      i < ArraySize(suffixes);
      i++
   )
   {
      string key = EntryKey(
         ticket,
         suffixes[i]
      );

      if(GlobalVariableCheck(key))
      {
         GlobalVariableDel(key);
      }
   }
}

として削除します。

ここで削除するのはエントリー時の7項目だけです。

決済時の相場環境はGlobalVariableに保存していないので、削除する必要はありません。


今回作った仕組み

今回の処理を改めて整理すると、

① Entry

OrderSend()
    ↓
ticket取得
    ↓
エントリー時の相場環境を取得
    ↓
GlobalVariableSet()


② Position

エントリー時情報を
GlobalVariableで保持


③ Exit

OrderClose()
    ↓
決済成功
    ↓
決済時の相場環境を取得


④ Log

エントリー時情報
        +
決済時情報
        +
取引結果
        ↓
trade_log.csv


⑤ Cleanup

DeleteEntryState()
        ↓
GlobalVariableDel()

となります。

これで零号機は、

「どんな相場でエントリーし、その後どんな相場になり、最終的にどうなったのか」

を記録できるようになります。


零号機は「結果」だけでなく「過程」を記録する

今回も、売買ロジックそのものを改善したわけではありません。

エントリー条件や決済条件は変えていないため、今回の改修だけでバックテストの成績が良くなるわけではありません。

しかし、Chapter2を進めるための重要な材料が増えました。

これまでは、

取引
 ↓
結果

を中心に見ていました。

これからは、

エントリー時の相場環境
        ↓
      取引
        ↓
決済時の相場環境
        ↓
      結果

として分析できます。

例えば、

ATRは拡大したのか
BB幅は拡大したのか
バンドとの距離はどう変化したのか

といった相場環境の変化と損益を結び付けることができます。

これは、Chapter1で見つけた「4~24時間の取引が弱い」といった現象の原因を探すうえでも使えるはずです。

零号機は今回、単に「取引した」という記憶だけでなく、

その取引の前後で相場がどう変わったのかを振り返るための記憶

を持てるようになりました。


次回 ― 記憶をPythonへ渡す

MQL4側の記録機能ができたので、次はそのデータをPythonへ渡します。

次回は、

trade_log.csv
       ↓
     Python
       ↓
trade_base.csv

という処理を作ります。

trade_log.csvは、零号機が記録した生の取引データです。

Pythonのpandasで読み込み、

  • 列構成の確認
  • 日時型への変換
  • 数値型への変換
  • 欠損値の確認
  • 異常値の確認
  • 分析しやすい形式への整理

を行います。

さらに今回、

Entry ATR / Exit ATR
Entry BB Width / Exit BB Width

の両方を保存できるようにしたので、Python側では将来的に、

ATRの変化量
BB幅の変化量

といった新しい特徴量も作れるようになります。

MQL4の役割は、経験を正確に記録すること。

Pythonの役割は、その経験からパターンを探すこと。

次回は、零号機の「記憶」を分析可能なデータへ変換していきます。

ランダムウォークへの挑戦⑭ | 零号機の「記憶」をPythonへ渡す ― trade_log.csvを分析用データに整える(2026/8/5)
はじめに前回は、MQL4を改修して、零号機が取引したときの情報を記録する仕組みを作りました。エントリーが成立した瞬間に、ATRBB幅バンドまでの距離スプレッドエントリー時刻曜日バー時刻などを取得し、取引が決済されるまでGlobalVaria…

関連記事

ランダムウォークへの挑戦㉓|最高PFは本当に強いのか。Relative Band Distanceを時間分割で比較する(2026/8/30)
ランダムウォークへの挑戦㉒|Q3の境界をずらしても優位性は残るのか(2026/8/30)
ランダムウォークへの挑戦㉑|Q3の優位性は時間が変わっても残るのか(2026/8/29)
ランダムウォークへの挑戦⑳|零号機の利益は「一部の大勝ち」に支えられているのか(2026/8/20)
ランダムウォークへの挑戦⑲|BAND_DISTANCEをATRで割って「相対的なブレイクの強さ」を分析する(2026/8/19)
ランダムウォークへの挑戦⑱|バンドからの距離で零号機のエントリー位置を分析する(2026/8/19)
ランダムウォークへの挑戦⑰|ATR×BB幅で零号機の「得意な相場」を16種類に分解する(2026/8/14)
ランダムウォークへの挑戦⑯|ボリンジャーバンドの幅で零号機の得意な相場を探る(2026/8/11)
ランダムウォークへの挑戦⑮|零号機は「荒れた相場」に強いのか ― ATRと取引成績の関係をPythonで分析する(2026/8/9)
ランダムウォークへの挑戦⑭ | 零号機の「記憶」をPythonへ渡す ― trade_log.csvを分析用データに整える(2026/8/5)
ランダムウォークへの挑戦⑬ | 零号機に「記憶」を与える ― mql4でエントリーから決済までの相場環境を記録する(2026/8/2)
ランダムウォークへの挑戦⑫ | Chapter2「学習」始動 ー零号機は何を学ぶべきなのかー(2026/8/2)
ランダムウォークへの挑戦⑪ | 零号機の性格診断──Chapter1「観測」 完結(2026/8/1)
ランダムウォークへの挑戦⑩ | Pythonで資産推移とドローダウンを分析する(2026/8/1)
ランダムウォークへの挑戦⑨ | Pythonで取引の連勝・連敗を分析する(2026/7/28)
ランダムウォークへの挑戦⑧ | Pythonでポジションの保有時間別に成績を分析する(2026/7/26)
ランダムウォークへの挑戦⑦ | Pythonでエントリー曜日と決済曜日から零号機を分析する(2026/7/23)
ランダムウォークへの挑戦⑥ | Pythonでエントリー時間と決済時間から損益を分析する(2026/7/22)
ランダムウォークへの挑戦⑤ | Pythonで月別損益をグラフ化する(2026/7/5)
ランダムウォークへの挑戦④ |Pythonで「零号機」の基本成績を分析する(2026/6/11)
ランダムウォークへの挑戦③ | 環境設定(2026/5/26)
ランダムウォークへの挑戦➁ | 小目標3つ設定(2026/5/25)
ランダムウォークへの挑戦① | はじめに(2026/5/25)

コメント

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