自分のインジが「あとから矢印を足していないか」を測る方法 ── 62行の検証用EAと、結果の読み方
こんにちは。MT4/MT5のインジケーターを作って、GogoJungleで販売している lab.aiueo です。
今日は、インジの矢印が「本当にその時刻に出ていたのか」を、自分で測る方法を書きます。
20時45分の矢印は、翌日の14時45分に出ていた
9月13日、私のサインツール SMC-Signal を使っている方から、こういう趣旨のご連絡をいただきました。
つまり、矢印は18時間後に、過去の足へあとから付けられていた、ということです。
チャートを開いて見れば、9月10日20時45分の足に、きれいに矢印が出ています。そのあと価格が下がっていれば、「よく当たる矢印」に見えます。
でも、20時45分の時点では、その矢印はまだありませんでした。
見ているだけでは、気づけない
この種のずれは、チャートを眺めているだけでは見つかりません。
- 矢印が付くのは、数時間〜数日前の古い足
- 通知の範囲の外なので、スマホにも届かない
- 付いたあとは、最初からそこにあったように見える
ご連絡くださった方は、チャートの足の時刻と、ログに出た時刻を、両方書いてくださっていました。だから分かりました。
それがなければ、私も気づかないままだったと思います。
測ったら、4割でした
SMC-Signalは「確定した足でサインを出す」ことを大事にしてきた製品です。コードも、そのつもりで書いていました。
でも、足ごとに測って確かめたことは、ありませんでした。
そこで、MT4のストラテジーテスターで足を1本ずつ進めながら、矢印が「いつ」「何本前の足に」初めて現れたかを記録する道具を作りました。62行のEAです。
直す前の版で測った結果です(15分足、初期設定)。
| 通貨・期間 | 途中で現れた矢印 | 8本以上前の足に出たもの |
|---|---|---|
| EURUSD(6/1〜9/10) | 270本 | 98本(最大283本前) |
| ゴールド(7/1〜9/10) | 196本 | 83本 |
途中で現れた矢印の36〜42%が、8本以上前の足に、あとから出ていました。
283本前は、15分足でおよそ3日前です。
直した版では、どちらも0本になりました。
過去の足に、あとから矢印が差し込まれるイメージ
「ノーリペイント」には、2つの意味がある
この件で、言葉の使い方も考え直しました。
インジの説明でよく見る「ノーリペイント(描き直さない)」には、2つの意味が含まれていると思います。
- 一度出た矢印が、あとから消えたり動いたりしない
- 過去の足に、あとから矢印が増えない
私の製品は、1つ目は守れていました。2つ目が守れていませんでした。
そして2つ目は、過去チャートを眺めても見分けがつきません。
「過去チャートに並んでいる矢印が、その時刻に本当に出ていたかは、測らないと分からない」
測る道具を、そのまま出します
この記事では、私が使った検証用EAの全文と、使い方、結果の読み方を書きます。お手持ちのインジでも試せるように書きました。
今回は、測る道具そのものが主役です。
仕組み
考え方は単純です。
MT4のストラテジーテスターは、過去の足を1本ずつ進めます。インジから見れば、リアルタイムで新しい足が1本ずつ確定していくのと同じです。
そこで、新しい足ができるたびに、インジの矢印を過去300本ぶん読みます。前回までに見たことのない矢印があれば、次の3つをファイルに書きます。
- 今、テスターが何本目の足を処理しているか
- 矢印は、どの足に付いたか
- それは、何本前の足か
確定した直後の足に出た矢印なら「1本前」です。それより前の足に初めて出てきた矢印は、あとから付けられたことになります。
検証用EAの全文
MQL4/Experts フォルダに保存して、コンパイルしてください。
//+------------------------------------------------------------------+
//| SMC-Signal の矢印が「いつ・何本前の足に」初めて現れたかを記録する |
//| 検証用EA。新しい足ごとに矢印バッファを読み、初出の矢印を |
//| tester/files/probe_.csv に書く。barNo=1 は適用時の再現分。 |
//| barNo>1 で shift>SwingLength+2 の行があれば、後から過去足へ |
//| 追加された矢印。 |
//+------------------------------------------------------------------+
#property strict
input string IndName = "SMC_Signal_109probe";
input int ScanBars = 300;
datetime g_last = 0;
datetime g_seen[];
int g_seenDir[];
int g_seenCount = 0;
int g_log = INVALID_HANDLE;
int g_barNo = 0;
bool Known(datetime t, int d)
{
for(int i = g_seenCount - 1; i >= 0; i--)
if(g_seen[i] == t && g_seenDir[i] == d) return true;
return false;
}
int OnInit()
{
g_log = FileOpen("probe_" + IndName + ".csv", FILE_WRITE|FILE_CSV|FILE_ANSI, ',');
FileWrite(g_log, "barNo", "now", "barTime", "dir", "shift");
return INIT_SUCCEEDED;
}
void OnDeinit(const int reason)
{
if(g_log != INVALID_HANDLE) FileClose(g_log);
}
void OnTick()
{
if(Time[0] == g_last) return;
g_last = Time[0];
g_barNo++;
for(int s = 1; s <= ScanBars && s < Bars; s++)
{
for(int b = 0; b < 2; b++)
{
double v = iCustom(NULL, 0, IndName, b, s);
if(v == EMPTY_VALUE || v == 0.0) continue;
datetime t = Time[s];
if(Known(t, b)) continue;
ArrayResize(g_seen, g_seenCount + 1, 1000);
ArrayResize(g_seenDir, g_seenCount + 1, 1000);
g_seen[g_seenCount] = t;
g_seenDir[g_seenCount] = b;
g_seenCount++;
FileWrite(g_log, g_barNo, TimeToString(Time[0]), TimeToString(t),
(b == 0 ? "BUY" : "SELL"), s);
}
}
}
OnTick の先頭で「足が変わったときだけ」動くようにしているので、足の途中の値動きでは何もしません。
書き換える所
1. 調べたいインジの名前
IndName に、調べたいインジのファイル名を入れます。拡張子(.ex4)は付けません。MQL4/Indicators フォルダに入っている名前そのままです。
初期値の SMC_Signal_109probe は、私が測るために用意したSMC-Signalのコピーの名前です。
テスターの「エキスパート設定」からも変えられます。
2. 矢印のバッファ番号
このEAは、インジの0番と1番のバッファを読みます。SMC-Signalでは、0番が買い、1番が売りの矢印だからです。
for(int b = 0; b < 2; b++)
...
(b == 0 ? "BUY" : "SELL")
ほかのインジでは、番号が違うことがあります。
MT4のデータウィンドウ(Ctrl+D)を開いて、矢印が出ている足にマウスを合わせると、どの欄に値が入るかで見当がつきます。はっきりしなければ、作者に聞くのが確実です。
3. 「矢印なし」の値
このEAは、値が EMPTY_VALUE か 0 の足を「矢印なし」と見なします。
多くのインジはこのどちらかですが、違う値を使うインジもあります。結果が明らかにおかしいとき(ほぼ全部の足に矢印がある、など)は、ここを疑ってください。
パラメータについて
iCustom にパラメータを渡していないので、インジは初期設定のまま動きます。
設定を変えて測りたいときは、インジの側で初期値を変えたものを用意するのが手軽です。
テスターの設定
私が使った設定です。
- エキスパートアドバイザ:このEA
- 通貨ペア・時間足:調べたいもの(私は15分足)
- モデル:始値のみ
- 期間:3か月前後(EURUSDは6/1〜9/10、ゴールドは7/1〜9/10)
- ビジュアルモード:不要
モデルは「始値のみ」で足ります。このEAは新しい足ができた瞬間にしか動かないので、足の途中の動きは使いません。
終わると、MT4のデータフォルダの中の tester/files に、probe_インジ名.csv ができます。
結果の読み方
CSVの列は5つです。
- barNo:テスターが何本目の足を処理していたか
- now:そのときの足の時刻
- barTime:矢印が付いた足の時刻
- dir:BUY か SELL
- shift:矢印が付いた足が、何本前だったか
読む順番は3つです。
1. barNo が1の行は、外す
テストを始めた瞬間、インジは過去の足をまとめて計算して、過去の矢印を描きます。これは「入れたときの再現」で、後出しではありません。barNo=1 の行は数えません。
2. shift が1なら、正常
確定した直後の足に出た矢印です。リアルタイムで見ていた人にも、その時点で見えていた矢印です。
3. shift が2以上なら、「作りとしての遅れ」か「後出し」か
ここが判断の分かれ目です。
インジによっては、作りとして何本か遅れて矢印を出すものがあります。
たとえば、高値や安値の山(スイング)を「左右に何本、低い足が並んでいるか」で決めるインジは、右側の足がそろうまで山が確定しません。その分、矢印は必ず遅れます。
この遅れは、遅れる本数が決まっていて、説明書に書いてあるなら、問題ではありません。
SMC-Signalの場合、山の確定に使う本数(初期設定で5本)に合わせて、通知の範囲を「直近7本」にしていました。なので、こう分けて数えました。
- shift 2〜7:作りとしての遅れの範囲
- shift 8以上:後出し
ご自分のインジで測るときは、説明書に「何本遅れる」と書いてあればその本数で分けます。書いていなければ、shift=1 以外を全部疑うところから始めるのが確実です。
Excelなら、COUNTIFS で「barNo が1より大きく、shift が8以上」の行を数えるだけです。
私の結果
直す前(Ver1.08)と直した後(Ver1.09)です。15分足、初期設定。
| 条件 | 版 | 途中で現れた矢印 | shift=1 | shift 2〜7 | shift 8以上 |
|---|---|---|---|---|---|
| EURUSD 6/1〜9/10 | 1.08 | 270 | 149 | 23 | 98(最大283本前) |
| 同上 | 1.09 | 175 | 175 | 0 | 0 |
| ゴールド 7/1〜9/10 | 1.08 | 196 | 101 | 12 | 83 |
| 同上 | 1.09 | 115 | 115 | 0 | 0 |
直した版では、途中で現れた矢印が、すべて確定した直後の足に出ています。
直す前の記録には、もうひとつ変な形がありました。
6月4日2時の足の時点で、58本前・71本前・95本前の足に、売りの矢印がまとめて3本付いていました。同じ瞬間に、過去の3か所へ同時にです。
これが、原因を突き止める手がかりになりました。
後出しが起きていた3つの原因
SMC-Signalは、BOS(構造のブレイク)を見つけると、5つの根拠で点数をつけて、基準点以上なら矢印を出します。
問題は、まだ矢印にならなかった過去のBOSを、新しい足が来るたびに、毎回採点し直していたことでした。
採点し直しても同じ答えが出るなら、問題はありません。ところが、採点の一部が「その足の時点」ではなく「今の状態」を見ていました。
1. ゾーンの加点が「今あるゾーン」を見ていた
価格がOB(オーダーブロック)やFVGの中にあれば、加点します。このとき、今有効なゾーンで判定していました。
あとからできたゾーンでも、過去の足に+1点が入ります。点数が基準に届けば、過去の足に矢印が出ます。
2. 連発を止める仕組みが、未来を数えていた
同じ向きの矢印が続けて出ないように、「反対向きのBOSが出るまでは、同じ向きを止める」仕組みがあります。
この判定が、候補の足より後に出た、反対向きのBOSまで数えていました。
トレンドが反転して反対向きのBOSが出た瞬間に、それまで止めていた過去の矢印が、まとめて解放されます。6月4日2時の「3本同時」は、これでした。
3. 上の時間足のデータ待ちを打ち切った採点を、あとでやり直していた
上の時間足のデータが届く前に、時間切れで「上位足の加点なし」として採点した構造がありました。データが届いたあとに採点し直すと、点数が上がって、矢印が出ます。
直し方
一度判定した範囲は、二度と採点しない
判定を終えたBOSの時刻の範囲を覚えておき、その範囲のものは採点し直さないようにしました。採点するのは、新しく現れたBOSだけです。
これで、リアルタイムで動いている間の矢印は、すべて確定した直後の足に出るようになりました。
判定済みの範囲を、ファイルに保存する
MT4を再起動したり、時間足を切り替えたりすると、インジは最初から計算し直します。そのとき判定済みの範囲を忘れていたら、また採点し直してしまいます。
そこで、判定済みの範囲をファイルに保存して、起動時に読み込むようにしました。中身は3行だけです(設定の指紋、範囲の始まり、範囲の終わり)。
- 判定済みの期間は、保存してある矢印だけを表示する
- インジが動いていなかった期間(MT4を閉じていた間など)は、次に開いたときに過去として再現する。通知はしない
- 矢印の出方に関わる設定を変えたら、範囲を捨てて、新しい設定で過去を再現し直す
テスターでは、保存しない
ここは小さな落とし穴でした。
テスターで保存を有効にすると、前回のテストで保存した「未来の範囲」が残ります。2回目以降のテストで、矢印が出なくなります。なので、テスターでは保存しないようにしました。
連発止めの判定に、上限をつける
候補の足より後に出たBOSは、数えないようにしました。
この修正で、過去チャートに表示される矢印は、以前より少なくなりました。これまでは、リアルタイムでは出ていなかった矢印が含まれていたからです。
再起動しても表示が変わらないか
保存の仕組みが効いているかは、テストを2回に分けて確かめました。保存をテスターでも有効にしたコピーを使っています。
- 1回目:6/1〜7/15
- 2回目:7/16〜8/14
2回目を始めたときに表示された矢印の内訳です。
| 2回目の条件 | 表示された矢印 | 1回目にリアルタイムで出ていたもの | それ以外 |
|---|---|---|---|
| 保存ファイルあり | 5 | 4 | 1 |
| 保存ファイルなし | 2 | 1 | 1 |
「それ以外」の1本は、1回目が終わったあとの足(7/15 20:00)で、止めていた期間の再現です。
保存ファイルがあれば、1回目にリアルタイムで見えていた矢印が、2回目にもそのまま残ります。なければ、一部しか残りません。
2回目の途中で現れた矢印は、どちらも52本すべてが shift=1 でした。
このやり方では測れないもの
- 矢印を、バッファではなくチャートの図形(オブジェクト)として描いているインジ。iCustom で読めないので、このEAでは測れません
- テスターとリアルタイムで、動きを変えているインジ。私の製品も、テスターでは保存を止めています。テストの結果が、そのままリアルタイムの動きと同じとは限りません
- 足の途中で出て、途中で消える矢印。このEAは足が確定した瞬間にしか見ないので、足の途中の出入りは記録しません
残っていること
正直に書いておきます。
- ゾーンの加点は、今も「今有効なゾーン」で判定しています。影響するのは、初めて入れたときや設定を変えたときの過去の再現だけで、リアルタイムの矢印があとから増えることは、もうありません
- MT5版にも同じ修正を入れましたが、テスターで測ったのはMT4版です
学んだこと
「確定足で出る」と言うなら、測らないといけない。
コードは、そのつもりで書いていました。測ってみたら、4割でした。
そして、ご連絡がなければ、測ろうとも思いませんでした。足の時刻とログの時刻を両方書いてくださったことが、すべての始まりです。本当にありがたかったです。
まとめ
- 過去チャートの矢印が、その時刻に本当に出ていたとは限らない。見ているだけでは区別できない
- テスターで足を1本ずつ進めて、矢印が「何本前の足に」初めて出たかを記録すれば、測れる
- barNo=1 は外す。shift=1 は正常。作りとしての遅れを超える shift は後出し
- 私の製品では、直す前に36〜42%が後出しだった。原因は、過去の候補を「今の状態」で採点し直していたこと
- 直し方は「一度判定した範囲は、二度と採点しない」。再起動に備えて、範囲を保存する
お手持ちのインジで、一度測ってみてください。何も出なければ安心材料になりますし、何か出れば、作者に伝える材料になります。
検証の数字を、喜ぶ前に疑う話は、前々回の記事にも書きました。
この修正は、SMC-Signal の MT4版 Ver1.09、MT5版 Ver1.02 で入っています。
SMC-Signal(MT4)
SMC-Signal MT5
本記事は、私自身の開発と検証の記録です。掲載したコードは検証用のもので、動作を保証するものではありません。ご利用はご自身の責任でお願いします。紹介しているインジケーターは相場分析を補助するツールであり、利益を保証するものではありません。投資判断はご自身の責任で行ってください。
最後まで読んでいただき、ありがとうございました。