# SMC ORDER BLOCK — PROJECT SEMANTIC SPECIFICATION v1 ```text 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) ```text 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) ```text 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) ```text 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) ```text 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) ```text 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) ```text 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) ```text 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) ```text 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) ```text - 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) ```text 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) ```text 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) ```text 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) ```text 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) ```text 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 ```text 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 ```