Complete guide to the NTL Smart Money Concepts (SMC) indicator — the pivot-based liquidity, structure, Break-of-Structure, Change-of-Character, conviction and trend-fib engine that powers SMC-style decision making in EAsiTrader. The same 18 bit-packed buffers documented here are what the EAsiScript SMC1(...) function reads, what the GroundedEvents pipeline exports to the AI providers, and what renders on the chart when you drag the indicator on yourself.
For how EAsiTrader strategies use the indicator, see the EAsiTrader User Guide. For scripting language details, see the EAsiScript User Guide. For the AI architecture that consumes the grounded events, see the AI Architecture Guide.
SMC is an MQL5 custom indicator that reads an OHLC series and produces, for every bar, a comprehensive snapshot of Smart Money Concepts state:
Signal() and Trend() helpers work unchangedInternally SMC depends on two helper indicators — one that tracks Average Bar Height so all distance thresholds adapt to volatility, and one that produces the raw pivot stream that pool detection and structure classification feed off. Their outputs are private; what SMC publishes is 18 output buffers, and every downstream consumer — chart drawing, EAsiScript, GroundedEvents for AI, CSV export — reads from the same buffer set. There is no "display-only" path that bypasses them; the on-screen graphics are simply a rendering of the buffer data.
When EAsiTrader loads a preset that includes an SMC indicator line, it instantiates SMC in "EA-instantiated" mode. In that mode:
SMC1(shift, buffer, lsr, mask) functionThe existing EAsiScript guide has a short SMC1 section covering the most common buffer reads; this document is the long-form companion that explains the full feature set, the bit layouts of every buffer, and how all the pieces fit together.
Every SMC decision starts with a pivot point — a bar whose high (for BSL / HH / LH structure) or low (for SSL / HL / LL structure) is more extreme than its neighbours. SMC scans the recent bar history for candidate pivots and retries with weaker candidates if the strongest one fails a downstream filter.
Bar strength needs a careful explanation here because SMC uses it differently from the rest of EAsiTrader, and the difference matters when you set the inputs.
min(bars-to-the-left, bars-to-the-right) that the pivot dominates. A strength-7 SMC pivot has 7 lower-high bars on the left and 7 lower-high bars on the right. This makes the filter more selective, but it also means a pivot can only be accepted after enough bars have closed to its right.Larger strength, in either sense, means a cleaner pivot and fewer false positives — but using an excessively large minimum will starve SMC of candidates.
The Min Bar Strength input (default 7, two-sided) sets the minimum bar strength required for any liquidity pool pivot. The separate ChoCH Min Bar Strength input (default 150, left-only) is used during ChoCh qualification and compares against the strength held at the structure point. See §5.
A liquidity pool is a horizontal line anchored at a recent pivot extreme where stop-loss orders and breakout buy-orders are assumed to cluster. Two kinds exist:
Buffers 0 and 1 hold the bit-packed SMC chain data for each side; buffers 2 and 3 hold the chain's latest active pivot price.
Not every pivot matters equally. SMC classifies each liquidity pool as internal or external based on how far price moved away from the pivot after it formed, measured in ABH (Average Bar Height) multiples.
Classification is a one-way latch: once a pattern is promoted to external, it stays external. Pending patterns can be promoted from internal to external as price continues moving away. For relay (non-formation) bars, the external bit is OR-propagated from the active chain, so a single read of SMC1(0, 0, 48, 1) gives a fast "any active BSL in the chain is external" answer without traversal.
Set the Liquidity Classification input to 0 to disable classification entirely; all patterns will then be treated as internal and the external flag will always be 0.
A pool is swept when price crosses its pivot extreme:
On the sweep bar the sweptAge counter starts at 1 and then increments every subsequent bar up to a hard cap of 255. This is what lets SMC1(0, 0, 12, 255) answer "has BSL been swept in the last N bars?" without walking the chain.
A parallel counter — bslSweptExternalAge / sslSweptExternalAge in Buffer 14 — tracks bars since the most recent external sweep. It is independent of sweptAge: subsequent internal sweeps do not reset the external counter, so the counter always points at the most recent external sweep. This is crucial for strategies that only care about the big HTF liquidity targets.
SMC runs a second, independent structure engine on the same pivot stream. Every time a new high pivot is confirmed, it is compared to the previously classified high pivot's price:
Likewise for low pivots:
These four codes (1=HH, 2=LH, 3=HL, 4=LL) are written to Buffer 6 (StructureData) on the classification bar — which is the bar where the pivot is confirmed, not the pivot bar itself. The pivot's bar strength is packed into bits 36–43 of the same buffer slot.
The last 24 structure codes are kept in a rolling 50-bit sequence buffer (Buffer 15 — SequenceData) as 24 × 2-bit pairs. Bit layout is designed so that index 0 (bits 3:2) is the newest pivot and index 23 (bits 49:48) is the oldest; bits 0–1 hold the most recent BOS direction. EAsiScript can read individual slots directly (see §6.13 and §7) to test for sequences like "the last three swings were HL → HH → HL".
A BOS is a bar whose close breaks a recent structure point:
On a BOS bar, the engine writes the BOS type + bars-back-to-broken-level to Buffer 8 (BOSData) and the broken structure's price to Buffer 9 (BOSPrice). A Wyckoff cycle name — "Markup" / "Markdown" / "Accumulation" / "Distribution" — is derived for chart labels and grounded events.
A special case: a BOS whose direction opposes the preceding trend is upgraded to a ChoCh (Change of Character). This is where the interesting data lives.
A ChoCh is a BOS that changes the trend direction. The rules for promotion (all must pass):
s[0]==LL, s[1]!=HH (i.e. the market was making LLs and we're breaking out upward). For a bearish ChoCh, s[0]==HH, s[1]!=LL.On a ChoCh bar, SMC captures a fib anchor pair:
chochImpulsePrice — the bar's high (for bullish) or low (for bearish) wick, written to Buffer 10 on the ChoCh bar onlychochInvalidationPrice — the most recent opposite-side structure price, written to Buffer 11 on the ChoCh bar onlyand enters a transition state that persists until either:
The structure trend direction is a 5-bit code (Buffer 14, bits 16–20) classifying the current market regime. There are 19 states (0–18). The Name column is the internal label EAsiTrader uses; the Chart label column is what renders on the chart:
| Code | Name | Chart label | Meaning |
|---|---|---|---|
| 0 | RANGING | RANGING | No dominant trend direction in the lookback window |
| 1 | BULLISH | BULLISH | Confirmed bullish trend (≥80% HH/HL over lookback, default) |
| 2 | BEARISH | BEARISH | Confirmed bearish trend |
| 3 | STRONG_BULLISH | STRONG BULLISH | Bullish with confirming Bull BOS and strength ratio boost |
| 4 | STRONG_BEARISH | STRONG BEARISH | Bearish with confirming Bear BOS and strength ratio boost |
| 5 | VSTRONG_BULLISH | V.STRONG BULLISH | Bullish + BOS agreement + very high strength ratio |
| 6 | VSTRONG_BEARISH | V.STRONG BEARISH | Bearish + BOS agreement + very high strength ratio |
| 7 | WEAK_BULLISH_TRANSITION | WEAK BULLISH TRANSITION | Bull ChoCh seen, impulse distance < 3 ABH |
| 8 | MODERATE_BULLISH_TRANSITION | MODERATE BULLISH TRANSITION | Bull ChoCh, impulse distance 3–5 ABH |
| 9 | STRONG_BULLISH_TRANSITION | STRONG BULLISH TRANSITION | Bull ChoCh, impulse distance 5–8 ABH |
| 10 | VSTRONG_BULLISH_TRANSITION | V.STRONG BULLISH TRANSITION | Bull ChoCh, impulse distance ≥8 ABH |
| 11 | BULLISH_RETRACEMENT | [tier] BULLISH MITIGATION | Bull ChoCh active, price retraced ≥ the Retracement Min (%) threshold into the fib |
| 12 | WEAK_BEARISH_TRANSITION | WEAK BEARISH TRANSITION | Mirror of 7 for bearish |
| 13 | MODERATE_BEARISH_TRANSITION | MODERATE BEARISH TRANSITION | Mirror of 8 |
| 14 | STRONG_BEARISH_TRANSITION | STRONG BEARISH TRANSITION | Mirror of 9 |
| 15 | VSTRONG_BEARISH_TRANSITION | V.STRONG BEARISH TRANSITION | Mirror of 10 |
| 16 | BEARISH_RETRACEMENT | [tier] BEARISH MITIGATION | Mirror of 11 |
| 17 | BULLISH_TFIB_RETRACEMENT | [tier] BULLISH RETRACEMENT | Confirmed bullish trend + active TFib retraced by ≥ the Retracement Min (%) threshold |
| 18 | BEARISH_TFIB_RETRACEMENT | [tier] BEARISH RETRACEMENT | Mirror of 17 |
The transition tier (WEAK / MODERATE / STRONG / VSTRONG) is decided by scaled ABH distance thresholds: ≥80 → VSTRONG, ≥50 → STRONG, ≥30 → MODERATE, else WEAK. The distance is held in Buffer 14 bits 31–40 as an integer scaled ×10, so a value of 65 means "6.5 × ABH".
⚠ Mitigation vs. Retracement — the important naming distinction. Codes 11 and 16 render on the chart as "MITIGATION"; codes 17 and 18 render as "RETRACEMENT". The two words mean different things in NTL SMC usage:
- Mitigation (states 11/16) — during a ChoCh transition (not yet fully confirmed), price has pulled back into the ChoCh fib ladder. The market is returning to the ChoCh source to mitigate unfilled orders that were left at the broken structure. Entry here is counter-impulse: you're fading into the ChoCh leg, betting the new trend will resume.
- Retracement (states 17/18) — a confirmed trend has printed and an active TFib has been retraced into by ≥ the Retracement Min (%) threshold. This is the canonical "pullback in a trend" setup — entering with the established trend off a TFib level.
When reading your chart: MITIGATION = early, pre-confirmation; RETRACEMENT = confirmed, post-TFib. When reading buffer 14 from EAsiScript: use the numeric codes — 11/16 for mitigation, 17/18 for TFib retracement.
An auxiliary isContested flag (Buffer 14 bit 58) is set when the trend classifier observes conflicting evidence — most commonly a BOS that disagrees with the sequence-count direction. Contested states are capped at the base BULLISH/BEARISH tier and prevent HIGH conviction (see §5).
On each active ChoCh, SMC draws a four-level retracement — 38.2%, 50%, 61.8%, 78.6% — anchored at the ChoCh bar's wick (ChochFibImpulse, 0%) and the violated structure point (ChochFibInvalidation, 100%). The ladder rays right until the fib terminates.
Termination rules (first to fire wins):
While active, the fib ray-extends to the right; once terminated, it freezes at the termination bar. The underlying state in SMC uses the same logic to compute the ChoCH retracement percent (Buffer 14, bits 41–47) and to emit retracement-state trend codes (11/16).
A TFib is a second kind of fib ladder that only appears after a trend is already confirmed. It measures the immediate pullback potential of the most recent impulse leg:
Triggering rules (all must pass):
(impulse_close − previous_same_side_pivot_close) / ABH ≥ TFib Expansion (ABH) (default 1.0).(impulse_close − anchor_wick) / ABH ≥ TFib Impulse (ABH) (default 2.0).On trigger, the engine writes anchor and impulse prices to Buffer 12 and Buffer 13 on that bar only. The direction is inferred by the draw layer from the sign of impulse − anchor (positive = bullish, negative = bearish).
TFibs terminate on:
Once a confirmed trend coincides with an active TFib and price has retraced into it by ≥ the Retracement Min (%) threshold, the structure trend state flips to the bullish or bearish TFib retracement code (states 17 / 18). A synthesised strength distance is written to the ChoCh distance field so the chart label picks up the correct tier prefix ("STRONG BULLISH RETRACEMENT" etc.).
For every bar, SMC classifies a conviction tier and direction into Buffer 16 (ConvictionData). Three tiers + hysteresis:
A stable bit (Buffer 16 bit 4) is set when the (tier, direction) pair has held for the hysteresis window (a fixed 2-bar dwell — not user-facing). Before the bar count reaches the dwell window, stable is 0.
When the Timeframe input is Current and the indicator is the first SMC dragged on the chart (label slot 0), a top-right conviction dashboard is drawn: one "Conviction" title row + three dots (Low / Medium / High) that glow in the direction colour when active — bright when stable, dim until stable. Only label slot 0 renders the dashboard, to prevent stacked duplicates when multiple SMC instances are on the same chart. The dashboard is off by default and is enabled by a build-time flag — there is no user input for it.
For BOS labels and grounded-event metadata, the BOS type maps to a Wyckoff cycle phase:
| BOS Type | Wyckoff Cycle |
|---|---|
| Bullish BOS | Markup |
| Bearish BOS | Markdown |
| Bullish ChoCh | Accumulation |
| Bearish ChoCh | Distribution |
If you have multiple SMC instances on the same chart (e.g. one for M5, one for H1), they are automatically assigned label slots — the first dragged is slot 0, the second is slot 1, etc. This keeps their chart object names unique and offsets their debug stacks so labels don't collide. Only label slot 0 draws the conviction dashboard.
EAsiTrader instantiates SMC from an indicator creation string declared in the preset, of the form:
NTL\SMC(1,0,800,7,400,100,7.0,2.0,0.0,11,80,1,30,0,0,150,1.0,2.0,1,70,2).ex5,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17
The first 1 is the hidden "Created by an EA" flag. Parameters 1–20 correspond to the logic-affecting inputs in the order shown in §4.1–4.7. The trailing comma-separated list after the .ex5 is the read buffer list — EAsiTrader keeps buffer 0 through buffer 17 available for SMC1(...) reads. If you omit a buffer from that list, SMC1() calls targeting it will return 0.
Do not pass display-only inputs in the creation string. See the next subsection for why.
Nine inputs are display-only — they are used only when SMC is dragged onto a chart and are never part of an EA creation string:
When EAsiTrader creates an SMC instance it has no chart to draw on, so these inputs are silently ignored. If you add them to an EA creation string they will be consumed as extra positional parameters, shift every following input out of place, and break the indicator's configuration. Do not reference them from a preset when thinking about strategy logic either — their on/off state has no bearing on what appears in the buffers.
The one exception is that the underlying state behind some of these flags is still computed internally (for example, "is this ChoCh weak?" is still tracked even when Hide Weak ChoCh only affects drawing). Your EA can read that state directly from the buffers — §6 tells you where.
This section lists every input exactly as it appears in the SMC indicator's Inputs dialog. Names in the left column are the labels you see when you drag SMC onto a chart or review its settings in an EAsiTrader preset. The "Position" column is the positional slot inside an EA creation string (relevant only when you are hand-editing a preset); drag-on-chart users can ignore it.
Display-only inputs (§4.8) are never included in a creation string — they exist only for on-chart rendering.
| Input | Default | Position | Description |
|---|---|---|---|
| Created by an EA | false | 0 | Hidden flag that EAsiTrader sets automatically when it creates the indicator. Do not set this manually when dragging the indicator onto a chart. |
| Timeframe | Current | 1 | Timeframe the instance analyses. Leave at Current when the instance is tied to the chart's own timeframe. Picking an explicit timeframe is for multi-timeframe setups driven by an EA; the on-chart conviction dashboard only renders when this is set to Current. |
| Max Lookback In Bars | 800 | 2 | Maximum bars to search back for a valid pivot when forming a new liquidity pool. Larger values find older pivots but cost more CPU on the first load. |
| Min Bar Strength | 7 | 3 | Minimum pivot bar strength for liquidity pool detection. Measured as the two-sided count described in §2: the pivot must dominate this many bars on both sides. A pivot below this threshold is rejected even if it would otherwise pass the swing-size filters. |
| Max Width In Bars | 400 | 4 | Maximum width (in bars) a liquidity pool line can reach before it is auto-terminated. 0 disables the cap. |
| ABH Period | 100 | 5 | Bar count used to calculate Average Bar Height. ABH normalises every "distance in ABH" threshold SMC uses — swing sizes, excursion thresholds, ChoCh impulse distances, TFib expansion — so they auto-adapt to volatility. |
| Input | Default | Position | Description |
|---|---|---|---|
| Liquidity Classification: Int/Ext Threshold (ABH) | 7.0 | 6 | ABH multiplier for internal/external classification. A pool is promoted to external when its post-pivot excursion in ABH units reaches this threshold. Set to 0 to disable classification (all pools internal, external flag always 0). |
| Input | Default | Position | Description |
|---|---|---|---|
| Post Pivot Swing Size (ABH) | 2.0 | 7 | Minimum post-pivot swing size in ABH units. Rejects small, insignificant pivots before they become liquidity pools. Set to 0 to disable. |
| Pre Pivot Swing Size (ABH) | 0.0 | 8 | Minimum swing distance in ABH from the previous opposite-side pivot. Rejects pivots that lack a significant preceding move. 0 disables. |
| Input | Default | Position | Description |
|---|---|---|---|
| Structure Trend Lookback | 11 | 9 | Number of recent structure points to examine when computing the trend direction. Hard-capped at 24 (the sequence buffer depth). |
| Structure Trend Threshold (%) | 80 | 10 | Percentage of bullish or bearish pivots required to declare a confirmed trend (0–100). With the default 80, at least 9 of the last 11 structures must be bullish (HH/HL) for the state to become BULLISH. |
| Structure Reset | true | 11 | When a new ChoCh starts or an existing transition is invalidated, clamp the effective lookback to the number of structures formed since that event. Prevents pre-ChoCh pivots from polluting the trend vote. |
| Retracement Min (%) | 30 | 12 | Minimum retracement into a ChoCh fib or TFib before the trend state flips to a retracement code (11, 16, 17 or 18). |
| Input | Default | Position | Description |
|---|---|---|---|
| ChoCH Lookback (structures) | 0 | 13 | Extra structures to scan when testing a BOS for ChoCh promotion. 0 disables the opposite-side filter. |
| ChoCH Opposite Threshold (%) | 0 | 14 | Maximum percentage of opposite-side structures tolerated within the ChoCH Lookback when promoting a BOS to ChoCh. 0 together with a zero ChoCH Lookback disables this filter. |
| ChoCH Min Bar Strength | 150 | 15 | Minimum pivot bar strength (left-only count) required for a BOS to be promoted to a ChoCh. This is much higher than Min Bar Strength (default 7) because of the scale difference explained in §2: 7 is a two-sided count, 150 is a left-only count. |
| Input | Default | Position | Description |
|---|---|---|---|
| TFib Expansion (ABH) | 1.0 | 16 | Minimum HL→HH (bullish) or LH→LL (bearish) expansion in ABH multiples. Measured close-to-close between the impulse pivot and the prior same-side pivot. |
| TFib Impulse (ABH) | 2.0 | 17 | Minimum impulse leg in ABH multiples — measured from anchor wick to impulse close. |
| TFib Require Body Confirm | true | 18 | When true, the pivot bar's close must have traded beyond the previous same-side pivot before the TFib is accepted. Disabling this produces noisier triggers. |
| Min TFib Strength | 70 | 19 | Minimum structure-point bar strength (left-only count) required for a TFib to trigger. Setups on pivots below this are skipped. |
| Input | Default | Position | Description |
|---|---|---|---|
| Export Type | Both (2) | 20 | Which event types the AI export writes. 0 = Liquidity only, 1 = Structure only, 2 = Both. See §8 for the budgeting behaviour of each mode. |
These inputs affect only what is drawn on the chart when you drag SMC on manually. They are never included in an EA creation string — setting them in one is a configuration bug.
| Input | Default | Description |
|---|---|---|
| Hide Weak ChoCh | true | Hides ChoCh chart labels when the impulse distance is < 3.0 × ABH. The underlying trend state machine is unaffected — a hidden ChoCh is still counted as a ChoCh internally. |
| Draw TFibs (HL-HH / LH-LL) | true | Master toggle for TFib drawing. |
| Only Show V.Strong TFibs | false | When on, only TFibs whose trigger coincides with a V.Strong trend tier are drawn. |
| TFib Show Box | true | Draws a filled rectangle between the 38.2% and 78.6% levels. |
| Show Structure Labels | true | Draws HH / LH / HL / LL labels at each structure point. |
| Show BOS Labels | true | Draws BOS / ChoCh labels with the Wyckoff cycle text. |
| Show SMC Labels | true | Draws the BSL / SSL origin labels. |
| Chart Label Style | LabelOnly | Label rendering style (label only, label with box, etc.). |
| Font Size | 7 | Font size for every SMC chart label. |
This section walks through what SMC does on every bar, in plain language. It is intended to give traders enough mental model to reason about what is being shown on the chart — not to replace the source code as a specification.
On each new bar, SMC runs the same sequence of steps:
The pivot search only looks backward. From the current bar, SMC scans the Max Lookback window for a qualifying pivot. Each candidate is tested in order:
On success, the new chain link is written with its backlink to the previous link, swept-age counter, side flag (BSL or SSL), formation bit, swept bit (set if price has already broken the pivot between pivot bar and current bar), pattern size, pivot shift, terminated bit and the internal/external classification.
Structure classification uses the same pivot stream. Every new high pivot is compared to the previously classified high pivot price:
Low pivots are classified HL / LL symmetrically. Each classification:
Every bar's close is checked against the most-recent HH/HL (for a bullish BOS) and the most-recent LL/LH (for a bearish BOS). If a break is detected:
There are three paths into the BOS slot. A single bar can carry two BOS events:
The secondary-BOS slot is the reason Buffer 8 has both a bit-15 and a bit-31 formation flag — one for each slot.
On every chart refresh, SMC walks the visible bar range, finds every bar with a non-zero ChoCh fib impulse value, reconstructs the fib ladder from the (impulse, invalidation) pair, and scans forward from the ChoCh bar to find the termination point.
Termination hits the first of:
Active fibs extend to the right with a ray; terminated fibs freeze at the termination bar's time.
A TFib trigger candidate is tested on every structure classification:
Triggered candidates are held as pending and promoted to the active slot on the next bar where a qualifying trend state exists. Termination:
A setup whose termination resolves at or before its own trigger-confirmation bar is not rendered at all — it was invalidated before it would have been drawn.
The trend code is decided as follows:
The Contested flag is set when BOS direction disagrees with the percentage vote or when a tie is broken by the BOS. Contested trends are capped at base BULLISH / BEARISH and block HIGH conviction.
Conviction looks at the current bar's trend, the previous bar's trend and the contested flag, and emits a tier and direction:
A dwell check sets the stable bit only if every intermediate bar over the hysteresis window (fixed at 2 bars) carried the same (tier, direction) pair. For the first couple of bars after indicator load, stable is 0 until the window fills.
There are 18 buffers, all written every bar, all readable from EAsiScript via SMC1(shift, buffer, lsr, mask). The bit layouts shown in this section are the authoritative reference.
About the code blocks in this section. The snippets below are pseudo-code showing what each
SMC1(...)call returns — they are not actual EAsiScript. EAsiScript scripts are single expressions returning a price (see §7 for real script examples); thename = SMC1(...)lines here are a convention used to label the value being read. Drop the left-hand side and use the right-hand side directly inside your actual entry, SL, TP or exit script.
| Idx | Name | Kind | Purpose |
|---|---|---|---|
| 0 | BSLData | uint64 bitpacked | Buy-side liquidity chain link (or relay) |
| 1 | SSLData | uint64 bitpacked | Sell-side liquidity chain link (or relay) |
| 2 | BSLPrice | double price | BSL latest active pivot price |
| 3 | SSLPrice | double price | SSL latest active pivot price |
| 4 | BSLSweptPrice | double price | BSL most-recent-sweep pivot price |
| 5 | SSLSweptPrice | double price | SSL most-recent-sweep pivot price |
| 6 | StructureData | uint64 bitpacked | HH/LH/HL/LL classification + strength |
| 7 | StructurePrice | double price | Pivot price at structure point |
| 8 | BOSData | uint64 bitpacked | Primary + secondary BOS slot |
| 9 | BOSPrice | double price | Price of broken structure level |
| 10 | ChochFibImpulse | double price | ChoCh fib 0% anchor (formation bar only) |
| 11 | ChochFibInvalidation | double price | ChoCh fib 100% anchor (formation bar only) |
| 12 | TFibAnchor | double price | TFib HL/LH anchor (trigger bar only) |
| 13 | TFibImpulse | double price | TFib HH/LL impulse (trigger bar only) |
| 14 | SweptExternalAge | uint64 bitpacked | Swept ext ages + trend/ChoCh diagnostics |
| 15 | SequenceData | uint64 rolling | 24-entry swing history + BOS direction |
| 16 | ConvictionData | uint64 bitpacked | Tier + direction + stable flag |
| 17 | SignalFlags | uint64 INDICATORSIGNALDATA | Standard sweep signal format |
There are two kinds of bars in every chain:
formed=1). All bit fields are valid on formation bars for drawing; a subset is safe for EA reads.formed=0). Only a subset of fields are meaningful. The fields that are meaningful on relay bars are real-time safe — they never reflect future data.Real-time safe on all bars (formation + relay):
backlink — always bars to the previous chain linksweptAge — monotonically increasing counterswept — sticky "has been swept" bitexternal — on relay bars, this is OR-propagated from the active chain (any active pattern external → relay bit set). Gives you O(1) "is there external liquidity active?" without traversal.type — constant per buffer (01 for BSL, 10 for SSL)formed — trivially safeNOT real-time safe (draw-layer internal — uses future bar data to assign):
size — pattern width in bars, determined retroactively when the pattern terminatespivotShift — bars from current to pivot, only finalised when the chain relaysterminated — only known with certainty after lookforwardexternal on formation bars — the formation-bar external bit is finalised later, once SMC has seen enough subsequent bars to measure the post-pivot excursion; do not read external specifically on formed=1 slotsWhen consuming from an EA, stick to backlink/sweptAge/swept/external-on-relay/formed/type and your reads will never repaint.
49-bit bitpacked liquidity chain data.
| Field | Bits | Range | Description |
|---|---|---|---|
| backlink | 0–11 | 0–4095 | Bars to previous chain link (0 = chain end) |
| sweptAge | 12–19 | 0–255 | Bars since sweep (0 = not swept, 1+ = bars elapsed) |
| type | 20–21 | 1 or 2 | 01 = BSL (Buffer 0), 10 = SSL (Buffer 1) |
| formed | 22 | 0 or 1 | 1 at pattern origin bar |
| swept | 23 | 0 or 1 | 1 when price broke the pivot |
| size | 24–35 | 0–4095 | Pattern width in bars — internal use only |
| pivotShift | 36–45 | 0–1023 | Bars from current to pivot — internal use only |
| terminated | 47 | 0 or 1 | 1 when pattern is no longer active — internal use only |
| external | 48 | 0 or 1 | 1 if external; safe on relay bars, internal only on formation bars |
EAsiScript reads:
BSLSweptAge = SMC1(0, 0, 12, 255) // bars since BSL sweep
SSLSweptAge = SMC1(0, 1, 12, 255) // bars since SSL sweep
BSLFormed = SMC1(0, 0, 22, 1) // 1 if new BSL formed this bar
SSLFormed = SMC1(0, 1, 22, 1) // 1 if new SSL formed this bar
AnyExternal = SMC1(0, 0, 48, 1) // 1 if active BSL chain is external
Plain double prices. On a formation bar, this is the newly-added pivot's price. On relay bars, it holds the newest active pattern's pivot price (or 0 if no active patterns remain on this side). A direct sweep check is as simple as:
BSLPrice = SMC1(0, 2)
// True when current bar's high >= BSLPrice
Plain double prices. Written on the sweep bar (sweptAge=1) and forward-propagated while sweptAge > 0 (up to 255 bars), then reset to 0. Combined with the SweptExternalAge buffer to distinguish internal from external sweeps:
BSLSweptPrice = SMC1(0, 4)
BSLExtAge = SMC1(0, 14, 0, 255)
// BSLSweptPrice represents an external sweep when BSLExtAge > 0
44-bit bitpacked structure classification.
| Field | Bits | Range | Description |
|---|---|---|---|
| backlink | 0–11 | 0–4095 | Bars to previous structure point (0 = chain end) |
| sweptAge | 12–19 | 0 | Reserved — currently unused, always 0 |
| structType | 20–22 | 0–4 | 0=None, 1=HH, 2=LH, 3=HL, 4=LL |
| formed | 23 | 0 or 1 | 1 at classification bar |
| swept | 24 | 0 | Reserved — currently unused, always 0 |
| pivotShift | 25–34 | 0–1023 | Bars from current to pivot — internal use only |
| terminated | 35 | 0 or 1 | 1 when structure point no longer active — internal use only |
| strength | 36–43 | 0–255 | Bar strength of the pivot (safe on formation bars and relay bars) |
Real-time safe fields: backlink, structType, formed, strength.
StructType = SMC1(0, 6, 20, 7) // newly-formed this bar (0 if none)
StructStrength = SMC1(0, 6, 36, 255) // pivot bar strength
Plain double price. Holds the pivot price of the most recent structure classification. Non-zero on every relay bar for as long as at least one structure exists on either side.
32-bit bitpacked primary + secondary BOS slots.
Primary BOS (bits 0–15):
| Field | Bits | Range | Description |
|---|---|---|---|
| bosType | 0–2 | 0–4 | 0=None, 1=Bullish BOS, 2=Bearish BOS, 3=Bullish ChoCh, 4=Bearish ChoCh |
| brokenLevel | 3–14 | 0–4095 | Bars back to the broken structure point |
| formed | 15 | 0 or 1 | 1 on the bar where the break was confirmed |
Secondary BOS (bits 16–31): same layout, shifted up by 16. Used on bars where a same-bar retroactive BOS needs to be stored alongside a primary BOS (PATH 2 in §5).
BOSType = SMC1(0, 8, 0, 7) // primary BOS type (0/1/2/3/4)
BOSBrokenBar = SMC1(0, 8, 3, 4095) // bars back to broken structure
BOS2Type = SMC1(0, 8, 16, 7) // secondary slot type (usually 0)
Plain double price. The level of the structure that was broken on this bar (non-zero when BOSData.formed=1).
Plain double prices. Written only at the ChoCh bar. Zero on every other bar — do not forward-fill these into indicator state without walking back to the most recent ChoCh bar yourself.
Reconstruct the fib ladder:
impulse = SMC1(N, 10) // find an N where this is > 0
invalidation = SMC1(N, 11)
level_382 = impulse + (invalidation - impulse) * 0.382
level_500 = impulse + (invalidation - impulse) * 0.500
level_618 = impulse + (invalidation - impulse) * 0.618
level_786 = impulse + (invalidation - impulse) * 0.786
Do not assume the ChoCh is still active just because the buffer slot is non-zero — it was frozen at that bar and you need to check the retracement percent in Buffer 14 or the current _inTransition state indirectly via the structure trend code in Buffer 14 bits 16–20.
Plain double prices. Written only at the TFib trigger bar. Direction is inferred by the draw layer from sign(impulse − anchor) — positive = bullish (HL→HH), negative = bearish (LH→LL).
anchor = SMC1(N, 12)
impulse = SMC1(N, 13)
// isBullish = impulse > anchor
60-bit bitpacked. This is the most important buffer for EAs — it carries the structure trend state, ChoCh diagnostics, swept external ages, and contested flags in a single slot that's updated on every bar.
| Field | Bits | Range | Description |
|---|---|---|---|
| bslSweptExternalAge | 0–7 | 0–255 | Bars since most recent external BSL sweep (0 = none) |
| sslSweptExternalAge | 8–15 | 0–255 | Bars since most recent external SSL sweep |
| structureTrendDirection | 16–20 | 0–18 | 19-state structure trend code (see §2 table) |
| structureTrendStrength | 21–30 | 0–1023 | max/min swing ABH ratio × 100; always ≥100 when non-zero |
| chochDistanceAbh | 31–40 | 0–1023 | ChoCh impulse distance in ABH × 10 (max 102.3 ABH) |
| chochRetracePct | 41–47 | 0–100 | ChoCh (or TFib, when in retracement override) retracement percent |
| structDebugLookback | 48–52 | 0–31 | Effective lookback used this bar (internal diagnostic) |
| structDebugBullish | 53–57 | 0–31 | Bullish-side count in the lookback (internal diagnostic) |
| isContested | 58 | 0 or 1 | BOS disagrees with sequence direction |
| abhBullish | 59 | 0 or 1 | Cumulative bullish ABH > bearish ABH |
EAsiScript examples:
StructureTrendDir = SMC1(0, 14, 16, 31) // 0..18
TrendStrength = SMC1(0, 14, 21, 1023)
ChochDistAbhX10 = SMC1(0, 14, 31, 1023)
ChochRetracePct = SMC1(0, 14, 41, 127) // 0..100
IsContested = SMC1(0, 14, 58, 1)
BSLExtAge = SMC1(0, 14, 0, 255)
SSLExtAge = SMC1(0, 14, 8, 255)
Note that bslSweptExternalAge operates independently from the side's own sweptAge. Subsequent internal sweeps do not reset this counter — it always points at the most recent external sweep on the given side.
50-bit rolling history.
| Field | Bits | Description |
|---|---|---|
| bosDirection | 0–1 | 0=none, 1=bullish, 2=bearish — most recent BOS direction, forward-filled every bar |
| swing[0] | 2–3 | newest structure (0=HH, 1=HL, 2=LH, 3=LL) |
| swing[1] | 4–5 | second newest |
| … | … | … |
| swing[23] | 48–49 | oldest structure in the history |
Reads:
BOSDirection = SMC1(0, 15, 0, 3)
LatestSwingType = SMC1(0, 15, 2, 3)
PreviousSwingType = SMC1(0, 15, 4, 3)
To inspect the most recent swing history from EAsiScript, read the relevant 2-bit slots directly. For example, to test "HL → HH → HL over the last three swings", check SMC1(0, 15, 6, 3) == 1 (oldest of the three — HL code is 1), SMC1(0, 15, 4, 3) == 0 (HH code is 0) and SMC1(0, 15, 2, 3) == 1 (newest — HL code is 1). The encoded slot values are 0=HH, 1=HL, 2=LH, 3=LL.
5-bit bitpacked.
| Field | Bits | Range | Description |
|---|---|---|---|
| tier | 0–1 | 0–3 | 0=None, 1=Low, 2=Medium, 3=High |
| direction | 2–3 | 0–2 | 0=None, 1=Bull, 2=Bear |
| stable | 4 | 0/1 | 1 when the (tier, direction) pair has held for ConvictionHysteresisBars prior bars |
ConvTier = SMC1(0, 16, 0, 3) // 0..3
ConvDir = SMC1(0, 16, 2, 3) // 0..2
ConvStable = SMC1(0, 16, 4, 1)
A high-conviction long entry rule might read ConvTier == 3 and ConvDir == 1 and ConvStable == 1.
The standard INDICATORSIGNALDATA uint64 bit-packed format (see Indicator/INDICATORSIGNALDATA_Reference.md for the complete schema). For SMC, only bits 2 (bearish sweep signal — SSL swept) and 3 (bullish sweep signal — BSL swept) of the flags byte are ever set. The signal data's identifier is 0x15 (SMC).
EAsiScript does not read this buffer directly — instead the standard Signal('SMC1'), Trend('SMC1') helpers decode it for you. Example:
isBullSweep = Signal('SMC1') > 0 // BSL sweep signal in this buffer's bar offset
isBearSweep = Signal('SMC1') < 0
trendDir = Trend('SMC1') // last trend bar offset
Every SMC buffer read goes through the SMC1(shift, buffer, lsr, mask) function:
shift — bar offset (0 = current bar, 1 = one bar back, …)buffer — buffer index 0–17lsr — "least significant bit" — the bit offset to shift right by before applying the mask (defaults to 0)mask — bit mask applied after the shift (defaults to 0, which means "read the whole double value")For plain-double buffers (2, 3, 4, 5, 7, 9, 10, 11, 12, 13), you pass only shift and buffer:
BSLPrice = SMC1(0, 2)
For bit-packed buffers (0, 1, 6, 8, 14, 15, 16, 17), you must supply both lsr and mask to extract a single field:
StructType = SMC1(0, 6, 20, 7) // 3 bits at offset 20 (structType)
The mask is the maximum value the field can take, not the raw bitmask. So a 3-bit field uses mask 7, an 8-bit field uses 255, a 10-bit field uses 1023, etc. EAsiScript does (value >> lsr) & mask internally.
EAsiTrader's general indicator-consumer functions work against SMC's signal buffer (Buffer 17), and a small family of SMC-specific helpers wraps the most common buffer reads so you do not have to remember bit layouts:
| Function | What it returns |
|---|---|
Signal('SMC1') |
+offset on a BSL sweep bar (bullish sweep signal), −offset on an SSL sweep bar, 0 otherwise. The offset is the bar shift back to the signal bar. |
Trend('SMC1') |
Bar offset to the most recent trend-change bar recorded in SMC's signal flags. |
SMCTrend('SMC1') |
The current SMC trend direction (bullish, bearish, ranging, transition states, mitigation, retracement) — the same 19-state code described in §2 and §6.12. |
SMCConviction('SMC1') |
The raw packed Conviction buffer value (Buffer 16). Compare it against a packed constant or extract tier/direction/stable bits as you would with SMC1. |
SMCFlow('SMC1', pattern) |
1 if the last three structure swings match the given 3-digit pattern (oldest→newest); 0 otherwise. Digits are 1=HH, 2=HL, 3=LH, 4=LL, 0=any. So 212 is HL→HH→HL, 010 is any→HH→any. |
SMCQuality('SMC1') |
A scalar from −2 (strong bearish) through 0 (neutral) to +2 (strong bullish), derived from the last three structure swings plus a BOS-direction tiebreaker. |
SMCChochFibPrice('SMC1', pct) |
The price at the given ChoCh fib percent (e.g. 38.2, 50, 61.8, 78.6) for the currently active ChoCh fib, or 0 if no ChoCh fib is active. |
SMCTFibPrice('SMC1', pct) |
The price at the given TFib percent for the currently active TFib, or 0 if no TFib is active. |
These helpers do the buffer reads and bit unpacking for you. Everything else — pivots, BOS, ChoCh state machine, raw conviction bits — is read through SMC1(shift, buffer, lsr, mask) as described in §7.1.
Setup: after a recent external BSL sweep, take a short when a new SSL pivot forms. Stop above the swept wick. Take profit at the last HL pivot.
The pieces we need from SMC, all read at bar 0:
> 0 and ≤ 20.1 on the bar where a new SSL pivot is confirmed.3 means HL.1 is a bullish BOS (used for the exit).EAsiScript scripts are single expressions that return a price (or 0 to do nothing). Each of the four scripts below is the whole script, pasted verbatim into the matching strategy setting:
Short Entry Script
SMC1(0, 14, 0, 255) > 0 && SMC1(0, 14, 0, 255) <= 20 && SMC1(0, 1, 22, 1) == 1 ? Bid() : 0
Short Initial SL Script — five-pip cushion above the swept BSL wick:
SMC1(0, 4) + 50 * Point
Short TP Script — the most recent HL price if there is one, otherwise no TP:
SMC1(0, 6, 20, 7) == 3 ? SMC1(0, 7) : 0
Short Exit Script — close the trade if SMC prints a fresh bullish BOS:
SMC1(0, 8, 0, 3) == 1 ? Ask() : 0
Notes: the Point constant is the symbol's pip-equivalent; the * 50 gives a 5-pip cushion on a 5-digit broker (1 pip = 10 points). The TP returning 0 means EAsiTrader simply opens the position without a take-profit, leaving the exit script in charge.
Setup: wait for a bullish ChoCh that has reached its mitigation state — Buffer 14 trend code 11, rendered on the chart as "BULLISH MITIGATION" — and enter long when price revisits the 61.8% fib level. Stop just below the 100% invalidation. Take profit at the 0% impulse.
The SMCChochFibPrice('SMC1', pct) helper makes the fib reads trivial — no need to walk back to find the ChoCh bar yourself or compute fib levels by hand. It returns the live price of the requested fib percent on the currently active ChoCh fib (or 0 if no ChoCh fib is active).
The state-code read is SMC1(0, 14, 16, 31) — Buffer 14 bits 16–20, the trend direction code from the 19-state machine. State 11 is the bullish ChoCh mitigation state (chart label "BULLISH MITIGATION", §2 / §11).
Long Entry Script — in mitigation state, fire when price closes at or below the 61.8% level:
SMC1(0, 14, 16, 31) == 11 && Close(0) <= SMCChochFibPrice('SMC1', 61.8) ? Ask() : 0
Long Initial SL Script — three pips below the 100% (invalidation) level:
SMCChochFibPrice('SMC1', 100) - 30 * Point
Long TP Script — the 0% impulse level:
SMCChochFibPrice('SMC1', 0)
Long Exit Script — close out as soon as SMC leaves the bullish mitigation state:
SMC1(0, 14, 16, 31) != 11 ? Bid() : 0
Notes: the entry script is the only one with a side condition (Ask() to open) — the SL and TP scripts simply return prices, and the exit script returns Bid() to close (or 0 to hold). A retracement that overshoots the 61.8% and continues past 78.6% will normally trigger the chart's invalidation rules and Buffer 14 will leave state 11 — at which point the exit script forces a flat position before any deeper damage.
Setup: take long entries only when conviction is HIGH bullish and stable, the trend is in the bullish TFib retracement state (Buffer 14 code 17), and price has reached at least the 50% TFib level. Stop a few pips below the 100% (HL anchor). Take profit at a 1R extension above the 0% (HH impulse).
The Conviction buffer (Buffer 16) bit layout is small enough to test as a single packed value: bits 0–1 tier (3 = High), bits 2–3 direction (1 = Bull), bit 4 stable (1). High + Bull + Stable encodes as 0b10111 = decimal 23. Reading the whole buffer with SMC1(0, 16, 0, 31) and comparing to 23 is the cleanest way to express "high-conviction stable bullish".
SMCTFibPrice('SMC1', pct) returns the live price of the requested TFib percent on the currently active TFib, or 0 if no TFib is active.
Long Entry Script — high-conviction stable bullish, in TFib retracement, price at or beyond the 50% level:
SMC1(0, 16, 0, 31) == 23 && SMC1(0, 14, 16, 31) == 17 && Close(0) <= SMCTFibPrice('SMC1', 50) ? Ask() : 0
Long Initial SL Script — three pips below the TFib's 100% (HL anchor):
SMCTFibPrice('SMC1', 100) - 30 * Point
Long TP Script — 1R projection above the 0% (HH impulse): impulse + (impulse − anchor):
2 * SMCTFibPrice('SMC1', 0) - SMCTFibPrice('SMC1', 100)
Long Exit Script — close out the moment SMC leaves the bullish TFib retracement state (the trend resumed, mitigated, or flipped):
SMC1(0, 14, 16, 31) != 17 ? Bid() : 0
Notes: the conviction packed-compare trick (== 23) only works when you want all three bits exactly. If you want "High tier and Bull direction, regardless of stability", drop down to two field reads: SMC1(0, 16, 0, 3) == 3 && SMC1(0, 16, 2, 3) == 1. The 1R TP arithmetic uses the closed-form rearrangement so the script stays as a single expression — no intermediate variables needed.
When EAsiTrader runs in an AI mode, SMC's buffers are walked to produce a JSON array of grounded events that the AI consumes as witness evidence. The GroundedEvents architecture exists to prevent hallucinations — the AI can only reference events that SMC actually saw.
The Export Type input selects which event families are emitted:
| Mode | Value | Contents |
|---|---|---|
| Liquidity | 0 | BSL/SSL patterns only — active, swept, expired |
| Structure | 1 | Structure points (HH/LH/HL/LL) + BOS events only |
| Both | 2 | Everything, with budget split as described below |
The export runs three phases to fit within a caller-supplied total event budget. When mode is Both, the budget is split so no single family crowds out the others:
status: "swept" or status: "expired" and includes an is_external metadata flag.SM_HH, SM_LH, SM_HL, SM_LL (with bar_strength) and BOS_<type>_<barsAgo> + BOS2_<type>_<barsAgo> for secondary slots (with broken_price and the mapped Wyckoff cycle name).At the end of the liquidity export, two summary fields are appended regardless of phase budgeting:
bsl_swept_external_bars_agossl_swept_external_bars_agoso the AI always has O(1) access to the most recent external sweep ages.
Three schema strings are published with the events so the AI knows the field set in use:
Each event has a unique id (the naming convention <TypeCode>_<barsAgo> makes them stable across refreshes for the same bar), a human-readable name, price, status, and a timeframe tag. Active liquidity events are emitted during the first phase; swept and expired events are emitted during the second.
You can place multiple SMC indicators on the same chart — for example, one on M5 and one on H1 — and they will not conflict. Two things to know:
Label slots. SMC counts how many other SMC indicators are already on the chart and assigns itself the next slot index (0, 1, 2, …). The slot offsets chart object names and debug-stack label positions so multiple instances don't overwrite each other. It also gates the conviction dashboard: only slot 0 renders the top-right panel. If you want the dashboard on a specific instance, make it the first one you drag onto the chart.
Plot buffer vs higher-timeframe paths. If Timeframe is left at Current, the instance uses the chart's own price series and writes to the 18 plot buffers directly on every tick. If you pick a different timeframe, the instance pulls a higher-timeframe series internally and is refreshed on every tick. The higher-timeframe path does not expose the buffers to the chart's indicator window — use it for EA reads via SMC1(shift, buffer, ...), not for visual analysis.
For the EA-instantiated case, typical EAsiTrader presets create multiple SMC instances with explicit timeframes and read them with SMC1 / SMC2 / SMC3 (the numbered variants mirror the SMC creation order in the preset). EAsiTrader handles caching internally so each timeframe's buffers are only recomputed when that timeframe actually ticks.
Defaults ship tuned for mid-timeframe index / major-pair trading (M15–H1). The knobs below cover the most common adjustments.
Symptom: noisy liquidity pools, shallow sweeps every few bars, no signal-to-noise.
Symptom: too many ChoCh markers, many of them barely breaking the prior structure.
SMC1(0, 14, 31, 1023) / 10.0 >= 3.0 is the EA-visible equivalent of the Hide Weak ChoCh check.Symptom: running SMC on M1/M5; sweeps and ChoCh fibs look bloated.
Symptom: running on H4/D1; signals are sparse and trends are obvious.
"SMC1 reads always return 0" — You probably forgot to include the buffer in the creation string's read-list. The part after .ex5, is a comma-separated list of buffer indices made available to SMC1(); any index not listed there returns 0. The standard list is 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17.
"My display-only inputs are not doing anything when I run in an EA" — Correct. They are silently ignored when EAsiTrader instantiates SMC. See §3 and §4.8. The indicator only consults them when it sees a chart (i.e. when dragged on manually).
"ChoCh fib never appears even though I see the ChoCh label" — The Hide Weak ChoCh display flag is independent of the fib drawing. Check that the ChoCh is not weak (impulse distance ≥ 3 ABH) and that you haven't exceeded the 200-bar hard cap. Also confirm the ChoCh hasn't been terminated by a same-direction BOS or body close beyond invalidation.
"The TFib draws for a few bars then disappears" — Normal when the setup is invalidated (same-direction BOS or close beyond the anchor). Check the termination-bar debug label; the draw layer skips TFibs whose termination resolves at or before the trigger confirmation bar.
"Conviction dashboard doesn't appear" — Two things to check:
"StructureTrendDirection reads 17 or 18 — I didn't know those existed" — Those are the TFib retracement overrides added on top of the base 17-state machine. They fire only when a confirmed trend coincides with an active TFib retraced by at least the Retracement Min (%) threshold. On the chart they render as "BULLISH/BEARISH RETRACEMENT" — distinct from states 11/16 which render as "MITIGATION". See §2 and §5.
"Why does the ChoCh bar's invalidation sometimes disagree with my eye?" — The fib invalidation is the most recent opposite-side structure price at the moment the ChoCh was detected — specifically the most recent HL/LL for a bullish ChoCh, or the most recent HL/LH for a bearish one. It is not the structure point that was broken (that's Buffer 9, BOSPrice). The two will often differ.
"How do I know if an EA read is real-time safe?" — See §6.2. Stick to backlink, sweptAge, swept, external (on relay bars), formed, type, structType, strength, all of Buffer 14 diagnostics, Buffer 15 sequence reads, Buffer 16 conviction, Buffer 17 signal flags. Avoid size, pivotShift, terminated, and formation-bar external.
formed=0). Carries forwarded state like sweptAge and the OR-propagated external flag; safe for real-time reads.formed=1). Holds the original classification data; a subset of fields are real-time safe.SMC1 section..set preset files that instantiate SMC via creation strings.Rev: 2026-04-16 (rewrote for traders: replaced internal class/enum/source-file names with user-visible input labels and chart-label vocabulary; clarified that SMC's Min Bar Strength is two-sided while ChoCH Min Bar Strength and Min TFib Strength remain left-only; documented the SMC-prefixed EAsiScript helpers — SMCTrend, SMCConviction, SMCFlow, SMCQuality, SMCChochFibPrice, SMCTFibPrice; rewrote §7 worked examples as real single-expression EAsiScript scripts using the actual Long/Short Entry/SL/TP/Exit Script settings; removed StructureFlow/StructureQuality references)