SniperGold_ML/docs/SMC_ORDER_BLOCK_SPEC_v1.md

17 KiB

SMC ORDER BLOCK — PROJECT SEMANTIC SPECIFICATION v1

Status  : PROJECT SEMANTIC SPECIFICATION (not "universal SMC ground truth")
Session : P3-S.5 — Formal Specification + Code-Conformance Audit (Order Block)
Date    : 2026-08-22
Scope   : The Order Block (OB) primitive as consumed by Engine 2 agents
          (AF_FindOrderBlock — Context agent C, Entry agent E), Engine 3 display
          (AF_CollectOBs), and the legacy v4.3/v4.4/v4.5 indicators
          (ProcessStructure RecordOB + v4.5 MTF RecordOB_mtf + entry gate
          InpEntryOnFVGorOB / FindEntryOB / Sweep->CHoCH->OB chain).
          OB is NOT a Feature Contract feature (f0-f18) — see §15.
Secondary reference : AF_CollectOBs (display), v4.3/v4.4/v4.5 RecordOB /
          RecordOB_mtf — implementation comparisons; the legacy structure-break
          definition is a SECOND historical definition (see §7 / A-2).
Provenance : P2 8d330343 | contract C44CC6F2 (P2-era) / 7b908b12 (committed)
             model 06df8452 | Forge HEAD 176880f (P3-S.4)

This document ESTABLISHES what "Order Block" (OB) means in the SniperGold_ML / Algo Forge project, derived from: (a) design intent (DESIGN.md agents C/E, display), (b) the current Algo Forge implementation (AF_FindOrderBlock / AF_CollectOBs), (c) the legacy indicator implementation (v4.3/v4.4/v4.5), (d) logical requirements (temporal causality, closed-bar, zone vs event). This document is NOT a claim of universal SMC truth; OB definitions outside this project (e.g. "last opposite candle before BOS") do not automatically apply here — the legacy structure-break definition IS part of the project's history and is recorded as a second definition (A-2), but the canonical current definition follows DESIGN.md and the Algo Forge implementation.


1. CONCEPTUAL DEFINITION (CORE)

Order Block in this project is a zone formed by an opposite-color candle immediately before a strong move:

  1. A closed candle B (the OB candle) whose color is OPPOSITE to the immediately following closed candle M (the move candle);
  2. The move candle M has a strong body: |Close(M) - Open(M)| >= 1.5 x average body (average body = mean |Close-Open| over the last 20 closed bars, AF_E2_LOOKBACK_AVG);
  3. Bullish OB: B is bearish (Close < Open) and M is bullish (Close > Open); Bearish OB: B is bullish and M is bearish;
  4. The OB zone = the FULL range of candle B: [Low(B), High(B)].

OB is a ZONE primitive (a persistent price region), NOT an event. The OB detector requires no structural break, no BOS/CHoCH, no displacement, and no liquidity interaction (canonical current definition — see §7 for the legacy second definition). OB detection is a pure opposite-color + strong-move rule.


2. CANDLE SELECTION (answer)

OB candle B       : the candle IMMEDIATELY BEFORE the strong move candle M
                    (M = B+1 in chronological terms).
Color of B        : determined by Close vs Open ONLY (Close < Open = bearish,
                    Close > Open = bullish). A doji (Close == Open) is neither
                    -> B does not qualify.
Full vs partial   : the OB uses the FULL candle range [Low(B), High(B)].
Body / wick       : no body-vs-wick selection; the entire candle is the zone.
MOVE candle M     : |Close(M) - Open(M)| >= 1.5 x avg body (AF_E3_MOVE_BODY).

Reason: DESIGN.md states "OB (opposite bar before a strong move)"; the current implementation (AF_FindOrderBlock / AF_CollectOBs) matches this exactly.


3. ZONE BOUNDARIES (answer)

High boundary : High(B)  (top of the OB candle)
Low boundary  : Low(B)   (bottom of the OB candle)
Body boundary : not used (full range)
Padding       : NONE in the definition. Consumer taps are consumer-side:
                Engine 2 trap tolerance +-0.3 x ATR (zone membership);
                legacy entry tap +-1 x ATR (entry gate).
Minimum size  : none in the definition (any positive range). Consumer-side
                minimum-size filters exist and DIVERGE (A-1):
                  - Engine 2 AF_FindOrderBlock : NO filter
                  - Engine 3 AF_CollectOBs     : >= 0.15 x ATR (AF_E3_OB_MIN_ATR)
                  - v4.3/v4.4/v4.5 RecordOB    : >= 0.15 x ATR (g_atr)
                A candle with range < 0.15 x ATR is still an OB per the
                definition but is filtered by display/legacy consumers.
One-tick edge  : the zone boundaries are exactly High(B)/Low(B); a close
                 exactly ON a boundary is NOT a mitigation event (strict
                 inequality, see §9); 1 tick beyond the boundary IS.

4. BULLISH / BEARISH SEMANTICS (answer)

Bullish OB (+1) : B bearish (Close(B) < Open(B)), M bullish (Close(M) > Open(M)),
                  |body(M)| >= 1.5 x avg. Zone = [Low(B), High(B)].
                  Expected role: support / continuation zone in an UP move.
Bearish OB (-1) : B bullish (Close(B) > Open(B)), M bearish, |body(M)| >= 1.5 x
                  avg. Zone = [Low(B), High(B)].
                  Expected role: resistance / continuation zone in a DOWN move.
Neutral (0)     : no qualifying pair in the window.

Direction = the direction of the MOVE candle (up move -> bullish OB). The OB
candle color is the OPPOSITE of the direction. This is the project rule; it is
not merely a variable sign (the definition comes from the pair (B, M) relation).
Symmetry is explicit (S-4 property test OB-T15).

5. STRUCTURAL PRECONDITION (answer)

CANONICAL (current) : NO structural precondition. The detector requires ONLY:
                      1) opposite color of B vs M, and
                      2) strong body of M (>= 1.5 x avg).
                      BOS / CHoCH / MSS / displacement / liquidity sweep / FVG:
                      NOT required for OB detection.

LEGACY second definition (v4.3/v4.4/v4.5) : OB is recorded ONLY at a STRUCTURE
  BREAK (close > last swing/internal pivot high for bullish, < low for bearish —
  BOS or CHoCH). The OB candle is the last (or highest-volume) opposite-color
  candle between the last opposite pivot and the break bar. This is a DIFFERENT
  formation rule (A-2), documented, not canonical.

SPEC DECISION : a detector that calls ANY opposite-color candle before a strong
  body an OB WITHOUT structural context is CONFORMING to the canonical current
  definition (DESIGN.md + AF_FindOrderBlock). The legacy structure-break rule is
  a separate historical definition.

6. FORMATION TIMING / CLOSED-BAR RULE (answer)

Observable : an OB at candle B is observable when the MOVE candle M = B+1
             CLOSES (the strong-body confirmation is a closed bar). The OB
             requires the pair (B, B+1) both closed.
Decision   : at decision time t (newest closed bar), valid OB candles B satisfy
             B+1 <= t. The NEWEST observable pair is (B = t-1, M = t) — the move
             candle may be the newest closed bar (NO 1-bar lag; contrast FVG S-6).
Timestamp  : the OB zone timestamp = open time of candle B (all implementations:
             AF_CollectOBs t=Time(obBar); v4.4 time[found]; v4.5 r[found].time).
Future     : NONE — mutating bars > t must not change the OB decision at t
             (property test OB-T19).
Repaint    : closed-bar lock; deterministic full recompute per bar.
Boundary   : the analysis region excludes the OLDEST cache bar as an OB candle
             (Engine-1 index scan starts at 1) — a cache-region artifact, not a
             semantic rule; irrelevant in the 700-bar runtime cache.

7. ORDER BLOCK LIFECYCLE (answer)

OB = ZONE (persistent) + FORMATION EVENT (the qualifying pair).

- FORMATION EVENT : the bar pair (B, M) — ONE event when the pair first
                    satisfies the rule (M closes).
- ACTIVE ZONE     : the zone [Low(B), High(B)] persists as ACTIVE (unmitigated)
                    for any number of bars. A zone untraded for 100 bars is ONE
                    OB, not 100 events.
- MITIGATED ZONE  : terminated by mitigation (§9). Display/legacy remove it from
                    the usable set; Engine 2 IGNORES the mitigation state
                    (BUG-P3S5-001).
- INVALIDATED / EXPIRED / CONSUMED : NOT modeled (§10).

Do NOT treat a persistent active zone as repeated OB formations — this is the
f7/f9/f18 duplication class, and OB detectors do NOT emit events (they maintain
zone lists / a newest-zone query), so no duplication exists (verified OB-T09).

8. MITIGATION (answer)

Canonical (display + legacy agree): MITIGATED when a subsequent bar j > B prints
  Close(j) < Low(B)   (bullish OB)  — close THROUGH the zone bottom.
  Close(j) > High(B)  (bearish OB)  — close THROUGH the zone top.

  = CLOSE-THROUGH FULL FILL (price closed beyond the far boundary of the zone).

Partial fill  : price entering the zone (touching a boundary, filling part of
                the gap) is NOT mitigation. PARTIALLY MITIGATED is NOT modeled.
Wick-only     : a wick penetrating the zone without a close beyond the far
                boundary is NOT mitigation (close-based rule).
Engine 2      : AF_FindOrderBlock has NO mitigation check at all (BUG-P3S5-001).
States        : UNMITIGATED / MITIGATED only.

9. INVALIDATION (answer)

INVALIDATION = NOT MODELED BY CURRENT SPEC

An OB is NOT invalidated by: full mitigation (that is MITIGATION, §8),
structure break, opposite displacement, opposite CHoCH, or time expiration.
A mitigated zone is simply no longer usable (display/legacy filter it out;
Engine 2 ignores the state entirely — BUG-P3S5-001).

10. MULTIPLE / OVERLAPPING ORDER BLOCKS (answer)

- Multiple OBs in sequence : each qualifying pair (B, M) produces its OWN zone;
  zones are NOT merged (except the display dedupe below).
- Nested / overlapping     : overlapping pairs produce separate zones.
- Same-direction consecutive OBs : separate zones, both kept.
- Opposite-direction OB before an old zone is mitigated : both zones coexist.
- New OB while old active : old zone stays (A-3; display keeps newest N).
- Display dedupe : AF_CollectOBs skips a zone whose top/bot are within
  0.5 x ATR of an already-collected zone ("simple dedupe"). Engine 2 (newest
  only) and legacy (keep all) do NOT dedupe. Keep-all vs dedupe = AMBIGUOUS
  (A-3).
- Prioritization : Engine 2 returns the NEWEST OB; display draws the newest N
  unmitigated; legacy draws the newest N unmitigated per type. No strength/
  volume prioritization in the current implementation (legacy InpVolumeOB /
  InpOBStyle=OB_HIGHEST_VOLUME is the historical volume mode, A-6).

11. BREAKER / MITIGATED OB DISTINCTION (answer)

BREAKER BLOCK = NOT IMPLEMENTED

No Breaker Block / breaker / flipped-OB code exists anywhere in the project
(verified: grep "breaker|Breaker" = 0 project-code matches; only two P3 documents
mention "breaker" as a FUTURE concept, outside this session's mandate).

The project models:
  original OB  -> zone -> MITIGATED (no longer usable).
It does NOT model:
  mitigated OB -> Breaker (flipped role) as a distinct concept.

If a reader wants a Breaker Block, the project does NOT define or implement it.
Do not add one in this session.

12. TIMEFRAME SEMANTICS (answer)

Engine 2   : OB is computed INDEPENDENTLY per agent-slot TF (H4 = Narrative,
             M30 = Context, M15 = Entry, M3 = Price Action); each slot has its
             own AF_FindOrderBlock query.
Display    : chart TF (M15 in the canonical deployment).
Legacy     : chart TF (swing + internal OBs) + v4.5 per-TF MTF OB (D1/H4/H1)
             via cache for display.
HTF as context  : supported by v4.5 (MTF OB) and Engine 2 (per-slot agents);
             NOT defined as a canonical rule ("HTF OB must act as M15 context").
M3 execution zone : NOT defined anywhere.
Cross-timeframe inheritance : not defined.

Status: the OB geometry/rule is TF-agnostic (same closed sequence -> same zone on
any TF); the canonical project OB (which TF's OB is the entry reference) =
SPECIFICATION AMBIGUOUS (same class as CHoCH G-4, sweep G-3, FVG A-3).

13. CONSUMER SEMANTICS (answer)

Chain : OB detector (AF_FindOrderBlock / AF_CollectOBs / RecordOB)
        -> zone state (top/bot/bull/mit)
        -> consumer:
           - Engine 2 C agent (context) : newest OB zone, price-in-zone fuzzy
             membership (weight 0.30), tolerance +-0.3 x ATR.
           - Engine 2 E agent (entry)   : newest OB zone (same query), ZONE +
             CONFIRMATION = setup rule.
           - Legacy v4.4/v4.5 entry     : FindEntryOB (unmitigated OB of the side
             whose mid is within +-0.2 x ATR of price) + tap test +-1 x ATR;
             +15 confluence; "Sweep->CHoCH->Bullish/Bearish OB (discount/premium)";
             pending "wait pullback to bullish OB" at zone top.
           - Engine 3 display           : visual boxes (newest N unmitigated).
           - ML features                : NONE (OB not in f0-f18).

Zone-vs-event in consumers : OB is consumed as a ZONE (persistent membership).
The C/E agents recompute the newest OB each bar — a persistent OB yields a
persistent membership, which is ZONE semantics, NOT repeated events (the
f7/f9/f18 stale-consumer class does NOT apply to OB by construction, OB-T09).
The cross-layer gap is MITIGATION (Engine-2 detector ignores mit) and AGE (the
newest OB can be hundreds of bars old, no freshness bound) — BUG-P3S5-001.

14. RUNTIME / TRAINING PARITY (answer)

OB IS NOT A FEATURE CONTRACT FEATURE.

- FEATURE_CONTRACT.md (f0-f18): no OB feature (the only "OB" text hit is "prOB"
  inside "SGMLProb", a false positive).
- EA runtime (AlgoForge_Backtest_Baseline.mq5): no OB computation (the "OB"
  hits are OrderSend + a comment "tanpa draw/OB/alert" stating OB is skipped).
- Python training pipeline (ml/**/*.py): 0 OB references.

Consequence: PARITY = N/A BY ABSENCE. The ML model was trained WITHOUT OB.
Any future use of OB as an ML feature requires a new Feature Contract entry
(out of scope). No runtime/training mismatch exists to document beyond the
absence itself.

15. SPEC DECISION SUMMARY (tabular)

# Aspect Decision
S-1 Formation opposite-color candle B immediately before strong-move candle M (body >= 1.5 x avg); canonical current definition
S-2 Candle selection B = full opposite candle (Close vs Open); doji excluded; FULL RANGE [Low(B), High(B)]
S-3 Zone boundaries top = High(B), bot = Low(B); no padding; min size none in definition (0.15 ATR consumer filters, A-1)
S-4 Direction +1 bullish (bearish B + bullish M), -1 bearish, 0 none; direction = move direction
S-5 Structural precondition NONE (canonical); legacy = BOS/CHoCH structure break (A-2 second definition)
S-6 Formation timing observable at M close (B+1 <= t); newest pair (t-1, t); NO 1-bar lag; timestamp = B open
S-7 Closed-bar all inputs <= t; no future visibility; deterministic
S-8 Lifecycle ZONE + FORMATION EVENT; one zone per pair; no event stream; no age expiry
S-9 Mitigation close-through full fill: Close < Low(B) bull / Close > High(B) bear; partial/wick NOT mitigation
S-10 Invalidation NOT MODELED
S-11 Overlap separate zones per pair; display dedupe 0.5 ATR (A-3); Engine-2 newest-only; legacy keep-all
S-12 Breaker NOT IMPLEMENTED (no code)
S-13 Timeframe Engine 2 per-TF independent; canonical = SPECIFICATION AMBIGUOUS (A-4)
S-14 Consumers C/E zone membership (newest OB); legacy entry gate (all unmitigated within tap); display; NO ML feature
S-15 Parity OB NOT an ML feature; PARITY = N/A BY ABSENCE

16. RECORDED AMBIGUITIES (SPECIFICATION AMBIGUOUS)

A-1  Minimum zone size: Engine 2 none / display 0.15 ATR / legacy 0.15 ATR.
     No canonical project threshold. NOT optimized here.
A-2  TWO OB DEFINITIONS IN ONE PROJECT:
     canonical current = opposite candle before strong move (DESIGN.md,
     AF_FindOrderBlock / AF_CollectOBs);
     legacy = opposite candle before STRUCTURE BREAK (v4.3/v4.4/v4.5 RecordOB,
     BOS/CHoCH on swing or internal structure, volume mode).
     The two rules can select different candles. The current definition is
     authoritative for the Algo Forge project; the legacy is historical.
A-3  Overlap handling: display dedupes zones within 0.5 x ATR; Engine 2 and
     legacy keep all. Keep-all vs dedupe intent NOT adjudicated.
A-4  Canonical OB timeframe (MTF vs M15): Engine-2 M15 slot explicit; HTF OB as
     M15 context / M3 execution not defined.
A-5  Consumer zone scope: Engine 2 newest-ANY (no mitigation filter) vs legacy
     all-unmitigated within tap vs display newest-N-unmitigated (BUG-P3S5-001).
A-6  Volume-weighted OB selection exists only in the legacy path (InpVolumeOB /
     InpOBStyle=OB_HIGHEST_VOLUME); the current implementation selects the last
     opposite candle only. Highest-volume vs last-candle intent NOT canonical.

17. PROVENANCE & CHECKPOINT

Forge HEAD (audit)      : 176880f8f3f17afb7e922a48ed953daa22c1515f (P3-S.4)
P3-S.4 spec (immutable) : docs/SMC_FVG_SPEC_v1.md
P3-S.3 spec (immutable) : docs/SMC_CHOCH_MSS_SPEC_v1.md
P3-S.2 spec (immutable) : docs/SMC_LIQUIDITY_SWEEP_SPEC_v1.md
FEATURE_CONTRACT        : C44CC6F2... (P2-era) / 7b908b12... (committed)
Reconciled sources      : see docs/P3_S5_ORDER_BLOCK_CONFORMANCE.md §A
Human verification      : CANCELLED