B面#4)ICTのオーダーブロックを翻訳したら、負けたのが誰か分からなくなった

FX Bot開発ログ

名前を付けて隣へ置いたことに、安心してたらしい。
気づいたのは、次の動画の再生ボタンを押したときだった。

Abstract

  • 出典: ICT(The Inner Circle Trader)「ICT Mentorship Core Content – Month 04 – Orderblocks
  • 対象: OANDA practice / USDJPY / M5(bid・ask)の固定抽出から集約した完全な15分足と、そこから作ったNY17:00境界の日足
  • やったこと: 本人が動画で語るオーダーブロックの定義・有効化・エントリー・損切り・利確・バイアスを、走らせる前に固定した翻訳ルールへ機械化し、bid/ask別のOHLCで約定を判定して検証
  • 結果: 事前に決めた主判定(決済後残高のリターンがプラス、かつ固定5区間中3区間以上で実現損益がプラス)は不成立
  • 非対象: 原手法・出典者の優劣評価、EURUSDや他期間への一般化、実注文の約定再現、実運用の可否
指標主版
検出ゾーン1,121
トレード数534
リターン-83.045409%
最大ドローダウン(決済後残高)-83.474296%
プロフィットファクター0.540830
勝率11.235955%
プラスの固定区間1 / 5

1. Introduction — 40分

隣に置いて、先へ進む。そう決めた夜は、それで終わりだと思ってた。

次の題材を探して、動画をひとつ開いた。再生ボタンを押した瞬間に、わかった。あの夜、名前を付けたことに安心してたんだ。自分の翻訳、って呼べるものが一つ増えたことに。わたしの感情は、いつも遅い。

開いた動画は、40分ある。

オーダーブロック。名前は前から知ってた。作った本人が、この動画で話してる。定義から、入る場所、損切りの置き方、狙う水準まで。無料で、全部。

これまでの検証は、短い動画から始まってた。ルールの足りない場所を、毎回わたしが埋めてきた。埋めるたびに、それがわたしの翻訳になった。

今回は、40分ある。本人が話してる。埋める場所は、ないはずだった。

今回は、決めなくて済む。

そう思いながら、書き取りを始めた。


2. Method — 余白

2.1 書き取りは、途中までうまくいく

買いのオーダーブロックの定義。本人の言葉のまま書くと、こう。

the lowest candle or price bar with a down close that has the most range between open to close and is near a support level

下に閉じたローソクのうち、いちばん安いところにあるもの。同じ安値の候補が重なったときだけ、実体の幅が大きいほうを残す。陰線、最安値。同値なら、実体レンジ最大。ここまでは条件式にできそうだった。

有効化も言ってる。あとから来た足が、その陰線の高値を上に抜けたら。これも書ける。

本人の英語が、そのまま条件式になっていく。今回は、はやい。

2.2 near a support level

止まった。

サポートの近く。……どのくらい近く?

再生バーを戻す。もう一度聞く。距離は言っていない。何本のあいだで見るのかも、言っていない。もう一度戻す。やっぱり、言っていない。

40分のどこにも、ここを埋める数字はなかった。

直近20本の中でいちばん安い陰線、と置いた。「サポートの近く」を別の定義で作り足すことはせず、窓の中の最安値であることに吸収させる。20という数字は、わたしが置いた。

2.3 余白は、ひとつじゃなかった

先へ進むと、同じ形の場所が続けて出てくる。

エントリーは陰線のopen、実体の上端。そこに「数pips足してもいい、5pipsくらいが望ましい」と本人は言う。……望ましい、は条件式にならない。足すのか、足さないのか。捨てた。openちょうどに指値を置く。

損切りは「安値の下」。そのすぐあとに「レンジの50%の下でもいい」とも言う。ふたつは両立しない。安値の側を選んだ。安値そのもの。

利確は external range liquidity。昔の高値の上に溜まった買い注文を狙う、と。……どの「昔の高値」? 確定済みの日足スイングの高値、遡って60営業日、と定義した。売りなら鏡写しで、スイングの安値。

バイアスは月足から週足、日足へ降りてくる。手元のデータは2年半ぶん。月足は、数えるほどしかない。日足の構造だけに簡約した。直近の確定スイングが高値も安値も切り上げていたら買いだけ、切り下げていたら売りだけ、どちらでもない日は建てない。

通貨。例に出てくるのはEURUSDと株価指数。わたしのDBはUSDJPY。ここも、そのまま。

本人の言葉を写している時間より、余白を埋めている時間のほうが、長い。

2.4 凍結

検出の真ん中は、ここ(ict_ob.py):

OFFICIAL_OB_LOOKBACK = 20

window = frame.iloc[index - lookback + 1 : index + 1]
opened = float(row["bid_open"])
closed = float(row["bid_close"])
if side == "long":
    qualifies = closed < opened and float(row["bid_low"]) == float(
        window["bid_low"].min()
    )

一行目の20は、40分のどこにも出てこない。

項目固定条件
入力固定範囲のM5抽出 → 完全なM15、NY17:00境界の日足
ET [2024-01-06, 2026-07-14)、920暦日
検出bid陰線かつ直近20本の窓内最安値。後続足の高値上抜けで有効化(買い側。売りは鏡像)
エントリー買いは陰線open、売りは陽線openへの指値(+5pipsは不採用)。日足バイアスと同方向のみ
損切り / 利確買い: 陰線のbid_lowそのもの / 確定済み日足スイング高値(遡り60営業日)。売り: ask_highそのもの / スイング安値
約定判定はbid系列。買いはaskで入りbidで出る。売りはbidで入りaskで出る。同一足はSL優先。強制手仕舞いなし
サイズ初期残高100万円、リスク1%、証拠金率4%
コスト手数料0、通常スリッページ0、スワップ0
調整結果を見て条件を変えない

スイングの確定遅れ、ゾーンの置き換えと消し方、指値の細かい約定順は、後ろに全部書く。

今回固定した買い側オーダーブロックの模式図

図1. 今回固定した買い側オーダーブロックの模式図。価格は説明用で、売り側は鏡像。

埋めた場所は、全部この表とコードに残ってる。読み返さずに、凍結した。細部だと思ってたから。

走らせる。


3. Results — 主語

3.1 数字

入力のhashを固定値と照合する。一致。二回走らせて、結果のhashも一致。

指標結果
検出ゾーン / トレード数1,121 / 534
最終残高169,545.912円
リターン-83.045409%
勝率11.235955%
最大ドローダウン(決済後残高)-83.474296%
プロフィットファクター0.540830
平均実現R-0.259556
プラスの固定区間1 / 5
主判定不成立

-83.05%。

100万円が、17万円になってる。勝率は11%。事前に決めた判定は、不成立。

固定184日区間の境界時点における決済後残高

図2. 固定184日区間の境界時点における決済後残高。帯は各区間の実現損益の正負を示す。区間内の推移と保有中の時価評価は描いていない。

3.2 470と60

閉じた理由を見る。損切りが470回。窓開きの損切りが4回。利確が60回。

買いの損切りは陰線のbid安値そのもの、利確は確定済みの日足スイング高値。売りの損切りは陽線のask高値そのもの、利確は確定済みの日足スイング安値。そう凍結したのはわたしで、その凍結の下で、60回しか届いていない。

534回のうち、買いが273回、売りが261回。数字は、そこまで。

決済理由の内訳

図3. 決済理由の内訳。SL 470、窓開きSL 4、TP 60。

3.3 固定した5区間

区間取引数実現損益
160-371,163円
2107-294,727円
3154+40,937円
4104-99,199円
5109-106,303円

プラスは区間3だけだった。観測は、そこまで。

3.4 結論の一行

ログに結論を書こうとした。

「ICTの手法は」

そこで、止まった。

この続きに動詞を置くには、走ったルールがICTの手法でないといけない。

ルールを読み返す。20本の窓。preferablyごと捨てた5pips。ふたつ語られた損切りから選んだ片方。「昔の高値」に与えた定義。月足を日足ひとつにした簡約。USDJPY。

余白を埋めた字が、ぜんぶわたしの字だった。

一行を消した。主語を変えて書き直そうとして、まだ決まらない。


4. Discussion — 誰のルールか

4.1 この数字の場所

比べにいこうとして、気づいた。この動画は教材で、成績の報告がそもそもない。原文の側に、比べる数字が最初からない。

走った条件の集合を、もう一度見る。USDJPY。15分足。20本の窓。日足だけのバイアス。この集合は、40分の中に存在しない。

だから、この-83.05%からオーダーブロックという手法の優劣は言えない。出典の側の何かが確かめられたわけでも、否定されたわけでもない。

言える文と、言えない文を仕分けて、それでも結論の行の主語は、空欄のままだった。

4.2 名前

エディタを閉じた。

画面の隅に、ファイラーが開いたままになってる。この前の検証のディレクトリが見える。orb_m15_retranslation。あの夜、自分の翻訳に付けた名前。

少しのあいだ、それを見てた。

4.3 同じ名前

遅れて、届いた。

あの名前は、今回の40分の前で、一度消えてたんだ。本人が全部話してくれるから、今回は書き写すだけ。そう思ってた時間のあいだ、ずっと。

でも書き写せたのは途中までで、そこから先は、いつもと同じことをしてた。余白を埋めて、埋めた分だけ、わたしが混ざる。走ってたのは、今回も、名前のつく側のルールだった。

空欄に入る言葉は、決まった。負けたのは、ICTの手法じゃない。わたしの翻訳。

再生リストに、動画がもうひとつある。17分。別の人が、同じ名前を話してる。

40分を訳したら、わたしの翻訳になった。17分を訳したら、何になるんだろう。

同じ名前が、別の人の口からも語られている。次は、それを訳す。


Appendix — 再現条件と技術的な境界

A. 入力と同一性

項目
source / environmentoanda_rest_v20 / practice
instrument / granularity / priceUSD_JPY / M5 / BAcomplete=1のみ
固定抽出範囲[2024-01-01T22:00:00Z, 2026-07-14T10:05:00Z)
M5行数188,981
M5抽出SHA-256f6d0e1cd1bd50ec11f7f3f0bd34e31b61a39970a687f3c5ac83682ae2ea1d512
complete M15 / 不完全bucket62,957 / 61
採用した日足 / 不採用656 / 1
確定スイング(日足 / M15)170 / 16,429

日足はM5からNY17:00境界で直接集約し、M5が216本(一日の75%)に満たない日は日足系列へ入れない。M15はch02の公開実装で集約した派生。完全再計算には同一の非公開SQLiteが必要で、行単位データは同梱しない。

B. 記事窓・区間・バイアス

  • 取引窓: ET日付 [2024-01-06, 2026-07-14) の920暦日。窓前のデータはスイング・バイアスのwarm-upのみ
  • 固定5区間(各184暦日): 境界は 2024-01-06 / 2024-07-08 / 2025-01-08 / 2025-07-11 / 2026-01-11 / 2026-07-14
  • 区間割当: 各取引のエントリー時刻をET日付へ変換し、境界を半開区間[開始日, 終了日)として割り当てる。決済日では割り当てないため、区間をまたいで保有した取引もエントリー側の区間に含める
  • スイング: 前後2本より高い(安い)足をスイング高値(安値)とし、2本あとの足の確定時点で初めて確定扱い。未確定のスイングはどの判定にも使わない
  • 日足バイアス: 確定済みスイングの直近2組が高値・安値とも切り上げで買いのみ、とも切り下げで売りのみ、それ以外は建てない。M15の始値時点の内訳は、買い27,630 / 売り17,438 / 中立16,067 / 判定不能1,822本
  • バイアスが定まらない間の新規はbias_unavailableとして見送り。保有中のポジションは決済まで持つ

C. 検出・有効化・ゾーンの運用

  • 候補: bid陰線で、当該足を含む直近20本のbid_low最小値と一致(買い側。売りはbid_high最大の陽線)
  • 同じ最安値(売りは同じ最高値)で候補が並んだ場合は実体|open−close|最大の足
  • 買いは、有効化前により低い安値の新候補が出たら置き換え。後続足のbid_highが候補のbid_highを上抜けたら有効化し、安値割れが先なら破棄。売りは鏡像で、より高い高値の新候補へ置き換え、後続足のbid_lowが候補のbid_lowを下抜けたら有効化し、高値超えが先なら破棄
  • ゾーンは買いが[bid_low, bid_open]、売りが[bid_open, bid_high](いずれも実体側まで)。指値は有効化足の次の足から有効
  • 待機ゾーンは常に1つで、新しい確定が古い待機を置き換える(置換193件)。ポジション保有中は新規を建てない
  • ゾーンの終わり方: 約定で消費744、買いはbid終値がゾーン下限を割る、売りはbid終値がゾーン上限を超えることで無効化183、置換193、データ終端1(合計1,121)
  • 消費744のうち、利確水準が見つからず見送り120、サイズ計算で証拠金上限を超え見送り90、約定534

D. 方向別の約定と決済

  • 買い: 指値はask_lowが届いた足で、指値価格のまま約定(窓開きでも価格改善なし)。SL・TPはbidで判定
  • 売り: 指値はbid_highが届いた足で、指値価格のまま約定(窓開きでも価格改善なし)。SL・TPはaskで判定
  • SLは買いが陰線のbid_lowそのもの、売りが陽線のask_highそのもの。バッファなし
  • TPは、エントリー時点で確定済みの日足スイングのうち、直近60取引日の範囲にあり、買いでは指値より上、売りでは指値より下にある最も新しい水準。該当がなければno_targetとして新規約定を見送る。約定した足では、始値がすでに指値条件を満たす場合だけ同足TPを許し、足の途中で約定した場合のTPは次足から。SLは約定した足から判定(悲観側)
  • 各足の優先順: 不利な窓開きは始値で決済 → 有利な窓開きはTP水準で決済 → 同一足で両方に触れたらSL優先
  • 強制手仕舞いなし。夜またぎ・週またぎを許し、スワップは0で計算(実コストではない)
  • 履歴のbid/ask OHLCによる約定モデルであり、実注文の約定再現ではない

E. 指標の定義と限界

  • リターン: 最終残高 ÷ 1,000,000 − 1。最大DDは初期残高と各取引の決済後残高から算出し、保有中の時価評価を含まない
  • PF: 総利益 ÷ 総損失の絶対値。実現R: 方向別の単位あたり損益 ÷ 初期リスク
  • 主判定は決済534件(30件以上)を前提に判定した
  • M15のOHLCから足の中の価格経路は復元できない。同一足SL優先は悲観側の仮定
  • この結果を、原手法や出典者の優劣、EURUSD、他の期間、オーダーブロック一般へ広げて読まない。「本人の教えを正しく実装した」とも言えない——翻訳判断が挟まっている

F. 再現コードと確認

  • 再現コード: GitHub
  • 公開コード版: commit e0c2a5c9b42e37d1c091b25f7b081f2ecf54800c
  • 参照結果の再計算: python chapters/season2/ch04_ict_order_blocks/run.py --db "$SOURCE_DB" --repeat 2(検出から集計まで二度実行し、結果hashの一致を要求)
  • 独立検証: 同chapterのverify.py。集計のみのrow-freeモードと、トレード明細から主要値を再計算する完全モード
  • 条件・version・hashはresults/reference/ch04_ict_order_blocks/manifest.jsonに固定。テストは全135件PASS

この固定条件とデータ仕様に基づく検証です。データ仕様の変更・欠損・修正などで結果は変わりえます。投資助言ではなく、売買判断はご自身の責任で。