| <p align="center"><img src="docs/images/logo.png" alt="SMC Zones logo" width="120"></p>
|
|
|
| # SMC Zones (MetaTrader 5 and MetaTrader 4)
|
|
|
| A free smart-money-concepts indicator that draws **order blocks, fair value gaps and BOS / CHoCH lines**, with optional
|
| liquidity sweeps, a session filter and a higher-timeframe layer, and sends an alert when a zone is created, touched or
|
| mitigated. Every zone is decided **on closed bars only** and never changes afterwards. Source for both editions, a Python
|
| reference of the rules, and the tests that were used to check that MT5, MT4 and Python all agree.
|
|
|
| **Website:** [allanninal.dev/mql5 (indicators)](https://www.allanninal.dev/mql5/#indicators) · [MT4 editions](https://www.allanninal.dev/mql5/#mt4) · [allanninal.dev](https://www.allanninal.dev)
|
| · **Contact:** message me on [LinkedIn](https://www.linkedin.com/in/allanninal/).
|
|
|
| 
|
|
|
| > It is an indicator, not a strategy. It draws zones and lines and places no trades. Nothing here is a profit claim
|
| > (see [Honest limits](#honest-limits)).
|
|
|
| ## Get it on the MQL5 Market
|
|
|
| | Edition | Platform | Price | Link |
|
| |---|---|---|---|
|
| | SMC Zones | MT5 | free | <https://www.mql5.com/en/market/product/201880> |
|
| | SMC Zones MT4 | MT4 | free | <https://www.mql5.com/en/market/product/202375> |
|
|
|
| The Market builds are the same calculation as the source in this repository.
|
|
|
| ## Contents
|
|
|
| 1. [What it is and who it is for](#what-it-is-and-who-it-is-for)
|
| 2. [Why it was built](#why-it-was-built)
|
| 3. [How it works](#how-it-works)
|
| 4. [Non-repainting: the proof and how it was tested](#non-repainting-the-proof-and-how-it-was-tested)
|
| 5. [Architecture and buffers](#architecture-and-buffers)
|
| 6. [Inputs, alerts, install and compile](#inputs-alerts-install-and-compile)
|
| 7. [Run the Python reference and the tests](#run-the-python-reference-and-the-tests)
|
| 8. [Honest limits](#honest-limits)
|
| 9. [Licence](#licence)
|
|
|
| ## What it is and who it is for
|
|
|
| **What:** the usual smart-money vocabulary, with the rule for each word written down and tested:
|
|
|
| - **BOS / CHoCH** lines: a *break of structure* when a close goes beyond the last unbroken swing in the direction of the
|
| trend, a *change of character* when it reverses the previous break.
|
| - **Order blocks**: the zone left at the start of the leg that broke the swing.
|
| - **Fair value gaps**: a three-candle gap of at least `k x ATR`.
|
| - Optional **liquidity sweeps** (a wick beyond a swing that closes back inside), a **session filter** (only create zones and
|
| sweeps inside chosen server hours) and **zones of a higher timeframe** drawn as outlines.
|
| - A zone is **mitigated** by the rule you choose: touch, midpoint, far-edge wick, or a close beyond the far edge.
|
|
|
| **For:** traders who use these concepts and want to know exactly *when* a zone is created and *when* it ends, and who want
|
| it to stay that way tomorrow. Also for developers who want 16 documented buffers to read with `iCustom`.
|
|
|
| **Not for:** anyone who expects a zone to predict a reaction. A zone marks where a rule fired on closed bars.
|
|
|
| | | |
|
| |---|---|
|
| |  |  |
|
| |  |  |
|
|
|
| Image notes: the charts are drawn by the Python reference on broker history (the same numbers the indicator shows); the alert
|
| text is the indicator's real text but the pop-up and phone card around it are mock-ups; the Data Window panel is a mock-up
|
| of the buffer map. They are illustrations, not terminal captures. More images, including the MT4 versions, are in
|
| [`docs/images/`](docs/images).
|
|
|
| ## Why it was built
|
|
|
| Smart-money indicators are everywhere, so this is not a gap-filling product. The reasons, stated with the evidence we actually have:
|
|
|
| - **Crowded, and the claims cannot be checked.** A scan of the MQL5 Market in October 2026 found many free and paid SMC
|
| tools (the best-known free one has over 50 reviews). Almost all say "non-repainting"; none we read published a test or
|
| stated when a zone is created. Several did not say what counts as "mitigated".
|
| - **Demand exists but is spread thin.** On the MQL5 Freelance board, 116 of 2,014 scraped jobs (Nov 2025 to Oct 2026) were in
|
| the SMC / order block / FVG / liquidity group, median budget 50 USD, about 30 applicants per job. People want it; the
|
| supply side is saturated.
|
| - **So the offer is trust and tidiness, not features.** Exact rules, a test that compares MT5, MT4 and an independent
|
| Python version bar by bar, and a probe that re-reads every buffer after the bar closed.
|
| - **Free on purpose.** Our own comparison said a new tool cannot be clearly better than the free leader on features, so it is
|
| free and its value is the evidence.
|
|
|
| ```mermaid
|
| mindmap
|
| root((SMC Zones))
|
| Problem
|
| Many SMC tools, few stated rules
|
| Non-repainting claimed, rarely tested
|
| Unclear when a zone ends
|
| Design rules
|
| Decide on closed bars only
|
| Creation bar and mitigation bar set once
|
| You choose the mitigation rule
|
| Proof
|
| Python reference
|
| 16 buffers compared bar by bar
|
| Tester repaint probe
|
| Market validation
|
| ```
|
|
|
| ## How it works
|
|
|
| ### The rules, step by step
|
|
|
| Let `O, H, L, C` be a bar's open, high, low, close and `i` the bar index (oldest = 0). Direction `d = +1` is bullish, `-1`
|
| bearish. Everything at bar `i` is decided from bars `0..i` only; the last bar of the chart (the forming one) is never used.
|
|
|
| 1. **ATR**: Wilder's smoothing of the true range, seeded with the simple average of the first `n` values (default `n = 14`).
|
| 2. **Swing**: bar `p` is a swing high if each of the `s` bars to its left has a strictly lower high and each of the `s` bars
|
| to its right a high not above it (a swing low the mirror). It is known at bar `p + s`, never earlier (default `s = 3`).
|
| 3. **BOS / CHoCH**: a close beyond the newest unbroken swing high (bullish) or low (bearish). It is a CHoCH when the previous
|
| break went the other way, otherwise a BOS. The first break ever is a BOS.
|
| 4. **Order block**: take the bar from the broken swing to the break bar with the lowest low (bullish) or highest high
|
| (bearish), call it `org`. If `org` is a candle against the move, the block candle is the last of the run of
|
| against-candles starting at `org`; otherwise the nearest against-candle among the 3 bars before `org`; otherwise `org`.
|
| Bullish zone: top = high of the block candle, bottom = lower of the two lows; bearish is the mirror.
|
| 5. **Fair value gap** at bar `i`: bullish if `L[i] - H[i-2] >= k x ATR[i]`, bearish if `L[i-2] - H[i] >= k x ATR[i]`
|
| (default `k = 0.2`). The zone is the gap.
|
| 6. **Liquidity sweep**: a bar wicks beyond an untaken swing (at most 60 bars old) by at least `0.1 x ATR` and closes back
|
| inside. Every swing wicked through is marked taken, whether or not the bar closed back inside.
|
| 7. **Mitigation** (checked on bars after the zone's creation bar), your choice: *touch* (a wick reaches the near edge),
|
| *midpoint*, *far-edge wick*, or *far-edge close* (a bar closes beyond the far edge). A midpoint exactly on the wick counts,
|
| within a relative `1e-10`, because `(top + bottom) / 2` can be one unit in the last place off.
|
| 8. **Touch**: a bar whose wick reaches the near edge of a live zone that was not already inside on the bar before.
|
| 9. **Session filter** (optional): zones and sweeps are only created on bars whose open hour (server time) is inside
|
| `[start, end)`.
|
|
|
| Per bar the engine always runs in this order: mitigation and touch of older zones, sweeps, fair value gap, break and order
|
| block, and then it looks for the swing that became known `s` bars back.
|
|
|
| ### Per-bar algorithm
|
|
|
| ```mermaid
|
| flowchart TD
|
| A[Closed bar i] --> B[ATR update]
|
| B --> C{ATR ready?}
|
| C -- no --> S[Look for the swing s bars back]
|
| C -- yes --> D[1 Older live zones: mitigated? touched?]
|
| D --> E[2 Liquidity sweep of an untaken swing?]
|
| E --> F[3 Fair value gap ending at bar i?]
|
| F --> G[4 Close beyond the newest unbroken swing?]
|
| G -- yes --> H[BOS or CHoCH, build the order block]
|
| G -- no --> S
|
| H --> S
|
| S --> W[Write the 16 buffers for bar i]
|
| W --> X{Last closed bar and not history load?}
|
| X -- yes --> Y[Alert for the events of bar i]
|
| X -- no --> Z[Done]
|
| ```
|
|
|
| ### Zone life cycle
|
|
|
| ```mermaid
|
| stateDiagram-v2
|
| [*] --> Live: created on a closed bar (never earlier)
|
| Live --> Live: price outside the zone
|
| Live --> Touched: a wick reaches the near edge for the first time
|
| Touched --> Live: price leaves the zone
|
| Touched --> Touched: re-enters, counted again
|
| Live --> Mitigated: the chosen rule fires on a closed bar
|
| Touched --> Mitigated: the chosen rule fires on a closed bar
|
| Mitigated --> [*]: end bar is fixed, kept only if you ask
|
| ```
|
|
|
| ### Alert flow
|
|
|
| ```mermaid
|
| sequenceDiagram
|
| participant T as Terminal
|
| participant I as SMC Zones indicator
|
| participant H as Alert helper
|
| participant U as You
|
| T->>I: OnCalculate (history load, prev_calculated = 0)
|
| I->>I: run the engine over every closed bar
|
| I-->>H: nothing (never alert during history load)
|
| T->>I: OnCalculate (a new bar closes)
|
| I->>I: step the engine on the bar that just closed
|
| I->>H: SignalAlert(events of that bar, bar time, live = true)
|
| alt newer than the last alert and not in the tester
|
| H->>U: one message with all events (pop-up, sound, push, e-mail)
|
| else same bar again or tester run
|
| H-->>I: nothing sent
|
| end
|
| ```
|
|
|
| ### How many zones the settings make (measured)
|
|
|
| Zones created per 1,000 bars on XAUUSD H1 broker history, for three of the input sets used in the tests (order blocks plus
|
| fair value gaps). Source: [`tests/results/parity-mt5.txt`](tests/results/parity-mt5.txt) (68,410 bars each). This counts zones
|
| only. It says nothing about whether they work.
|
|
|
| ```mermaid
|
| xychart-beta
|
| title "Zones created per 1,000 bars, XAUUSD H1"
|
| x-axis ["Defaults", "Swing 5 + session 7-16", "Swing 2, gap 0.5 ATR"]
|
| y-axis "zones per 1,000 bars" 0 --> 220
|
| bar [186.2, 64.7, 149.2]
|
| ```
|
|
|
| Defaults: swing 3, ATR 14, gap 0.2 x ATR, order block mitigated by a close, gap by a wick. Second: swing 5, touch rules,
|
| session filter 07:00-16:00. Third: swing 2, ATR 10, gap 0.5 x ATR, far-edge wick and close rules.
|
|
|
| 
|
|
|
| ## Non-repainting: the proof and how it was tested
|
|
|
| "Non-repainting" is easy to claim. Here is what was actually run. Raw result files are in [`tests/results/`](tests/results).
|
|
|
| **1. Three implementations, compared bar by bar.** The Python reference
|
| ([`tests/reference.py`](tests/reference.py)) states each rule above in code. The MT5 and MT4 indicators were dumped bar by
|
| bar (all 16 buffers) in the MetaTrader Strategy Tester and [`tests/check_parity.py`](tests/check_parity.py) compared each
|
| dump with the reference. Pass means: on every closed bar every buffer is equal (prices within 1e-9 relative, counts
|
| exactly, empty where the reference has nothing).
|
|
|
| | | MT5 | MT4 |
|
| |---|---|---|
|
| | dumps compared | 36 (4 symbols x M15/H1/H4 x 3 input sets) | 37 (the same 36 + one every-tick EURUSD H1) |
|
| | bars compared | 1,122,912 | 761,453 |
|
| | order blocks | 70,816 | 47,570 |
|
| | fair value gaps | 78,770 | 61,946 |
|
| | zones mitigated | 144,950 | 105,899 |
|
| | BOS / CHoCH | 80,616 | 54,733 |
|
| | liquidity sweeps | 41,441 | 26,013 |
|
| | result | ALL PASS | ALL PASS |
|
|
|
| Symbols: EURUSD, XAUUSD, GBPJPY, BTCUSD. Input sets: defaults; swing 5 with touch rules and a session filter; swing 2 with a
|
| 0.5 x ATR gap and far-edge rules. Sources: [`tests/results/parity-mt5.txt`](tests/results/parity-mt5.txt),
|
| [`tests/results/parity-mt4.txt`](tests/results/parity-mt4.txt). The MT5 and MT4 histories differ in length on the FX pairs,
|
| which is why the bar counts differ.
|
|
|
| ```mermaid
|
| xychart-beta
|
| title "Items compared, Python vs indicator (all 0 differences)"
|
| x-axis ["Order blocks", "Gaps", "Mitigated", "BOS/CHoCH", "Sweeps"]
|
| y-axis "items compared (thousands)" 0 --> 160
|
| bar [70.8, 78.8, 145.0, 80.6, 41.4]
|
| line [47.6, 61.9, 105.9, 54.7, 26.0]
|
| ```
|
|
|
| Bars: MT5. Line: MT4.
|
|
|
| **2. Repaint probe.** A probe records which signal buffers are set on each bar *at the moment it closes*, then reads the same
|
| bars again at the end and counts any value that changed. It also counts any signal ever shown on the still-forming bar.
|
|
|
| | Run | Closed bars checked | Signals seen at close | Changed afterwards | Signals on the live bar |
|
| |---|---|---|---|---|
|
| | MT5, EURUSD H1, every tick, 10,411,052 ticks | 4,644 | 13,988 | **0** | **0** |
|
| | MT4, 37 runs combined | 756,852 | 129,285 | **0** | **0** |
|
|
|
| Source: [`tests/results/repaint-summary.md`](tests/results/repaint-summary.md). The MT5 probe ran once (EURUSD H1, default
|
| inputs); the MT4 probe ran on every dump run. "Signals" counts every set value among the probed buffers (new zones, structure
|
| breaks, sweeps).
|
|
|
| **3. Market validation.** Both Market builds passed the MQL5 Market's automated product validation before publication (the
|
| Market's own check, not part of this repository).
|
|
|
| ```mermaid
|
| flowchart LR
|
| R[reference.py<br/>Python, rules as code] --> P
|
| S5[MT5 indicator] --> T5[Tester script<br/>DumpIndicator<br/>every bar to CSV]
|
| S4[MT4 indicator] --> T4[Tester EA<br/>SMCZonesDump + Dump4.mqh<br/>CSV + repaint log]
|
| T5 --> P[check_parity.py<br/>16 buffers, 1e-9]
|
| T4 --> P
|
| S5 --> RP[RepaintProbe EA<br/>values at close vs final]
|
| T4 --> RL[repaint log<br/>per run]
|
| P --> V{all pass?}
|
| RP --> V
|
| RL --> V
|
| V -- yes --> M[Market validation]
|
| V -- no --> F[fix, rerun everything]
|
| ```
|
|
|
| ### Why the design cannot repaint
|
|
|
| - The engine is a state machine: `Step(i)` reads bars `0..i` only, so what it decided about bar `i` cannot change later.
|
| - A zone's creation bar and its mitigation bar are written once. A swing is only used `s` bars after it formed.
|
| - The forming bar is never stepped; its buffers are always empty.
|
| - Alerts fire only for the bar that just closed, only after the history load, once per bar, and never in the tester.
|
| - What *does* move: the right edge of the drawing (live zones are extended a few bars past the last bar). That is the
|
| drawing, not a signal.
|
|
|
| ## Architecture and buffers
|
|
|
| ```mermaid
|
| flowchart TB
|
| subgraph MT5["mql5/Indicators/SMCZones"]
|
| A5[SMCZones.mq5<br/>inputs, buffers, drawing, alerts]
|
| E5[SmcEngine.mqh<br/>CSmcEngine state machine]
|
| B5[SignalAlerts.mqh<br/>alert inputs, TfName, SignalAlert]
|
| A5 -- include --> E5
|
| A5 -- include --> B5
|
| end
|
| subgraph MT4["mql4/Indicators/SMCZones"]
|
| A4[SMCZones.mq4]
|
| E4[SmcEngine.mqh<br/>exact copy]
|
| B4[SignalAlerts.mqh<br/>MT4 edition]
|
| A4 -- include --> E4
|
| A4 -- include --> B4
|
| end
|
| subgraph TESTS[tests]
|
| R[reference.py]
|
| C[check_parity.py]
|
| D5[mql5: DumpIndicator, RepaintProbe, Params.mqh]
|
| D4[mql4: SMCZonesDump.mq4, Dump4.mqh]
|
| C --> R
|
| end
|
| D5 -. IndicatorCreate .-> A5
|
| D4 -. iCustom .-> A4
|
| ```
|
|
|
| ```mermaid
|
| classDiagram
|
| class SMCZones {
|
| +InpSwing int
|
| +InpATR int
|
| +InpOBMit enum
|
| +InpFVGMin double
|
| +InpFVGMit enum
|
| +InpHTF timeframe
|
| +OnInit()
|
| +OnCalculate()
|
| +Redraw()
|
| +Events()
|
| }
|
| class CSmcEngine {
|
| +zones SSmcZone[]
|
| +breaks SSmcBreak[]
|
| +sweeps SSmcSweep[]
|
| +Reset()
|
| +Step(i)
|
| }
|
| class SignalAlerts {
|
| +InpAlertPopup bool
|
| +InpAlertSound bool
|
| +InpAlertPush bool
|
| +InpAlertEmail bool
|
| +SignalAlert()
|
| }
|
| class reference {
|
| +smc_zones()
|
| }
|
| SMCZones --> CSmcEngine : one for the chart, one for the higher timeframe
|
| SMCZones --> SignalAlerts : alerts
|
| reference ..> CSmcEngine : same rules, compared by check_parity
|
| ```
|
|
|
| ### `iCustom` buffer table (for EA developers)
|
|
|
| All 16 buffers are data only (nothing is plotted); the zones are chart objects. Empty value is `EMPTY_VALUE`. Read **closed
|
| bars** (shift 1 and higher). A buffer is set on the bar where the event was decided.
|
|
|
| | Buffer | Content |
|
| |---|---|
|
| | 0 / 1 | bullish order block created on this bar: top / bottom |
|
| | 2 / 3 | bearish order block created on this bar: top / bottom |
|
| | 4 / 5 | bullish fair value gap created on this bar: top / bottom |
|
| | 6 / 7 | bearish fair value gap created on this bar: top / bottom |
|
| | 8 | structure: +1 BOS up, -1 BOS down, +2 CHoCH up, -2 CHoCH down |
|
| | 9 | the broken swing's price |
|
| | 10 | sweep of a low (the swing's price), bar closed back above |
|
| | 11 | sweep of a high (the swing's price), bar closed back below |
|
| | 12 | number of zones mitigated on this bar |
|
| | 13 | number of live zones touched for the first time on this bar |
|
| | 14 / 15 | live bullish / bearish zones after this bar |
|
|
|
| `iCustom` parameters follow the input order. In MT5 the `input group` headings also count as string parameters when you
|
| build a handle with `IndicatorCreate` (see `tests/mql5/Include/IndTest/Params.mqh`). MT4 has no input groups, and its
|
| buffers are read with the usual series shift.
|
|
|
| ## Inputs, alerts, install and compile
|
|
|
| | Input | Default | Meaning |
|
| |---|---|---|
|
| | Swing strength | 3 | Bars on each side that make a swing |
|
| | ATR period | 14 | Wilder ATR length |
|
| | Draw order blocks / Order block is mitigated when | true / far edge, close | Zone rule |
|
| | Draw fair value gaps / Minimum gap, x ATR | true / 0.20 | Gap size |
|
| | Gap is mitigated when | far edge, wick | Zone rule |
|
| | Mark liquidity sweeps / Swing looked back / Wick beyond the swing | false / 60 bars / 0.10 x ATR | Sweeps |
|
| | Only create zones and sweeps in the session | false (07:00 to 17:00 server hour) | Session filter |
|
| | Also draw zones of this timeframe | current (off) | Higher-timeframe outlines, completed bars only |
|
| | BOS / CHoCH lines, keep mitigated zones | true / false | Display |
|
| | Draw zones created within / at most / extend live zones | 1000 bars / 80 zones / 12 bars | Display limits |
|
| | Fill the zones, colours | true | Appearance |
|
| | Alerts: new zone / touch / mitigated / BOS-CHoCH / sweep | true / true / false / true / false | Which events alert |
|
| | Pop-up / sound / push / e-mail | true / false / false / false | Delivery (push needs your MetaQuotes ID) |
|
| | Debug log for bug reports | false | Writes extra lines to the Experts tab, to attach when you report a problem |
|
|
|
| **Install from source.** Copy `mql5/Indicators/SMCZones/` into `<terminal data folder>/MQL5/Indicators/` (MT5) or
|
| `mql4/Indicators/SMCZones/` into `<data folder>/MQL4/Indicators/` (MT4), open `SMCZones.mq5` or `.mq4` in MetaEditor and
|
| press Compile (F7). Both compile with 0 errors (checked with the MetaEditor of a MetaTrader 5 and a MetaTrader 4 build on
|
| a Windows machine; the compiled files are not in the repository). Keep the three files of each edition together. The debug log needs the Chart Kit file as well: copy `mql5/Include/ChartKit/` (MT5) or `mql4/Include/ChartKit/` (MT4) into the `Include` folder of the data folder.
|
|
|
| ## Run the Python reference and the tests
|
|
|
| ```bash
|
| python3 -m venv .venv && . .venv/bin/activate && pip install -r requirements.txt
|
| ```
|
|
|
| ```python
|
| import sys; sys.path.insert(0, "tests")
|
| from reference import smc_zones
|
| # t, o, h, l, c are numpy arrays of bar times (epoch seconds) and OHLC, oldest first; the last bar is the forming bar
|
| buffers, zones, breaks, sweeps = smc_zones(t, o, h, l, c, swing=3, atr=14)
|
| ```
|
|
|
| To repeat the parity check on your own data:
|
|
|
| 1. Compile the indicator and the test tool for your platform (`tests/mql5/Scripts/DumpIndicator`, or
|
| `tests/mt4/SMCZonesDump.mq4` with `tests/mql4/Include/IndTest4/Dump4.mqh` in your `MQL4/Include/IndTest4/`; MT5 also
|
| needs `tests/mql5/Include/IndTest/Params.mqh`).
|
| 2. Run it for each symbol and timeframe with the input sets in `tests/configs.tsv` (MT5) or `tests/mt4/configs.tsv` (MT4).
|
| Each run writes one CSV per symbol and timeframe, tagged with the config name.
|
| 3. `python3 tests/check_parity.py <folder with the CSVs>` (add `--mt4` for MT4 dumps). It prints PASS or FAIL per file.
|
| 4. Repaint: run `tests/mql5/Experts/RepaintProbe` in the MT5 Strategy Tester (every tick); MT4 writes its repaint log with the dump.
|
|
|
| The price dumps used for the published numbers are not in this repository (they are broker price data).
|
|
|
| ## Honest limits
|
|
|
| - **Zones are not predictions.** Nothing here says a zone holds, that a CHoCH reverses the market, or that a sweep marks a
|
| turn. The numbers above are about *consistency* and *frequency*, never profit.
|
| - **One reading of smart-money concepts.** There is no standard definition. These are written-down, testable rules; another
|
| tool's order block can be a different candle and both can be called correct.
|
| - **Most zones end.** In the MT5 test dumps 144,950 of the 149,586 order blocks and gaps created (about 97%) were later
|
| mitigated. That is how the rules work, not a promise about any one zone.
|
| - **Lag is built in.** A swing is only known `s` bars after it formed, so BOS / CHoCH and the order block appear on the bar
|
| that breaks it, not when the turn started.
|
| - **Higher-timeframe zones** use completed bars of that timeframe only, so they appear when that bar closes.
|
| - **Scope of the tests.** Four symbols, three timeframes, three input sets, one MT5 repaint run. Other symbols, timeframes
|
| and settings are not covered by the published numbers. The MT5 build was not run on a live chart as part of these numbers.
|
|
|
| ## Licence
|
|
|
| Everything is © 2026 Allan Niñal under the
|
| [PolyForm Noncommercial License 1.0.0](LICENSES/PolyForm-Noncommercial-1.0.0.md): source-available, free for personal and
|
| other noncommercial use, not for commercial use. Each source file has an `SPDX-License-Identifier` line; the text is in
|
| [`LICENSE`](LICENSE). The licence applies to this source, not to anything you build or trade with the indicator. Trading
|
| involves risk; the software is provided as is.
|
|
|
| ---
|
|
|
| **Website:** [allanninal.dev/mql5](https://www.allanninal.dev/mql5/#indicators) · [MT4](https://www.allanninal.dev/mql5/#mt4) · [allanninal.dev](https://www.allanninal.dev)
|
| · Questions: message me on [LinkedIn](https://www.linkedin.com/in/allanninal/).
|