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:
- A closed candle B (the OB candle) whose color is OPPOSITE to the immediately following closed candle M (the move candle);
- 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); - Bullish OB: B is bearish (Close < Open) and M is bullish (Close > Open); Bearish OB: B is bullish and M is bearish;
- 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