Tectonic Structure Engine
- Libraries
-
Syarief Azman Bin Rosli
Hello and welcome to my official MQL5 profile!
I am Syarief Azman Bin Rosli, an algorithmic trading systems developer and quantitative software engineer with over a decade of specialized experience creating robust automated trading solutions for MetaTrader 5 and MetaTrader 4. - Version: 1.0
- Activations: 5
An MQL4 library that maps market structure for your EA, indicator or script: confirmed swings labelled HH, HL, LH, LL, EQH and EQL, break of structure (BOS), change of character (CHoCH), liquidity sweeps, order blocks and fair value gaps with fill tracking, and the position of price in the dealing range. It reads closed bars only and never repaints. It does not trade, draw or alert. You receive the compiled Tectonic_Structure_Engine.ex4; this page is the full API reference.
Quick Start
- Copy Tectonic_Structure_Engine.ex4 to MQL4/Libraries (File > Open Data Folder).
- Paste the #import block below into your program.
- In OnInit: h = TSE_Create("", 0, 3, 1000); optionally TSE_Configure.
- Call TSE_Update(h) in OnTick or OnCalculate. Without a new bar it returns 0 in about a microsecond.
- Read TSE_Trend, TSE_GetEvent, TSE_NearestZone and the rest; TSE_Release(h) in OnDeinit.
- Verify: run the example below in the Strategy Tester (any symbol, M15). The journal lists each event; the first update lists the whole history.
Import Declaration (Copy-Paste Ready)
#import "Tectonic_Structure_Engine.ex4" int TSE_Create(string symbol, int timeframe, int strength, int history_bars); bool TSE_Configure(int handle, int break_mode, double min_swing_atr, double equal_tol_atr, double fvg_min_atr, int atr_period); void TSE_Release(int handle); int TSE_Update(int handle); int TSE_Trend(int handle); int TSE_SwingCount(int handle); bool TSE_GetSwing(int handle, int index, int &side, double &price, datetime &time, int &label); int TSE_EventCount(int handle); bool TSE_GetEvent(int handle, int index, int &type, double &level, datetime &swing_time, datetime &break_time); bool TSE_GetLevels(int handle, double &swing_high, double &swing_low, bool &high_broken, bool &low_broken); double TSE_RangePosition(int handle, double price); int TSE_ZoneCount(int handle); bool TSE_GetZone(int handle, int index, int &kind, int &dir, double &top, double &bottom, datetime &time, int &state, double &fill); int TSE_NearestZone(int handle, int kind, int dir, double price, double &top, double &bottom); int TSE_GetStats(int handle, int &stats[]); int TSE_LastError(); string TSE_ErrorText(int code); string TSE_LabelText(int label); string TSE_EventText(int type); string TSE_ZoneText(int kind, int dir); string TSE_StateText(int state); #import
Codes
- Swing labels: 1 HH, 2 LH, 3 EQH (highs); -1 LL, -2 HL, -3 EQL (lows); 0 FIRST (no earlier swing on that side).
- Event types: 1 BOS UP, -1 BOS DOWN, 2 CHOCH UP, -2 CHOCH DOWN, 3 SWEEP HIGH, -3 SWEEP LOW.
- Zone kind: 1 fair value gap, 2 order block. dir: 1 bullish (support), -1 bearish (resistance). Texts: BULL FVG, BEAR FVG, BULL OB, BEAR OB.
- Zone state: 0 FRESH (untouched), 1 TESTED (price entered), 2 FILLED (FVG traded through), 3 BROKEN (OB closed through).
- Errors: 0 OK, -1 BAD HANDLE, -2 BAD PARAMETERS, -3 NO HISTORY, -4 NO FREE SLOT, -5 BAD INDEX. Text functions return UNKNOWN for other codes.
How Each Closed Bar Is Read
- Zones: a low inside a bullish zone (a high inside a bearish one) sets TESTED and raises fill, the deepest penetration in % of the zone height. An FVG becomes FILLED when price reaches its far edge; an OB becomes BROKEN on a close beyond its far edge (fill can reach 100% while the OB stays active).
- Swings: the bar strength bars back is a swing high when its high is above the strength bars before it and not below the strength bars after it (lows mirrored). A swing is reported strength bars late and never moves. With min_swing_atr above 0, the high minus the lowest low of the 2 x strength + 1 bars must be at least min_swing_atr x ATR. Label against the previous swing of the same side: within equal_tol_atr x ATR is EQH or EQL, otherwise HH or LH, LL or HL. The newest swing high and swing low are the break levels.
- Breaks: break_mode 0 needs a close beyond the level, 1 a wick. Breaking the swing high gives CHOCH UP when the trend was -1, otherwise BOS UP; the trend becomes 1 and the level is used up. Lows mirrored. In close mode a wick beyond with a close back inside is a SWEEP, once per level.
- Order block: on every BOS or CHoCH, the last opposite candle (bearish for an up-break) at or up to 10 bars before the extreme of the leg between swing and break; the zone is its high-low range.
- Fair value gap: third candle low above first candle high (bullish), or third high below first low (bearish), at least fvg_min_atr x ATR tall.
ATR is the simple average true range over atr_period bars.
API Reference
TSE_Create
symbol: "" or NULL = chart symbol; must exist. timeframe: 0 = chart period, else PERIOD_M1 to PERIOD_MN1. strength: 1-50. history_bars: 100-20000, built on the first update. Returns a handle 0-31, or -1 with BAD PARAMETERS or NO FREE SLOT. Defaults: break_mode 0, min_swing_atr 0, equal_tol_atr 0.10, fvg_min_atr 0.25, atr_period 14.
TSE_Configure
break_mode 0-1, min_swing_atr 0-10 (0 = off), equal_tol_atr 0-5, fvg_min_atr 0-10, atr_period 1-500. Clears the handle; the next TSE_Update rebuilds. Any value out of range: false, BAD PARAMETERS, nothing changed.
TSE_Release
Frees the handle for reuse. Call it in OnDeinit.
TSE_Update
Reads the closed bars not seen yet; the first call builds history_bars. Returns the number of new events (indexes 0 to n-1 of TSE_GetEvent), 0 without a new bar, or -1: BAD HANDLE, or NO HISTORY while fewer than 2 x strength + 4 bars are loaded (call again on the next tick). If the last bar read disappears (history reloaded), the handle rebuilds by itself.
int n = TSE_Update(h); if(n > 0) Print(n, " new events");
TSE_Trend
1 after an upward break, -1 after a downward break, 0 before the first break or for a bad handle.
TSE_SwingCount and TSE_GetSwing
Stored swings, newest at index 0: side (1 high, -1 low), price, time of the swing bar, label. Count -1 for a bad handle; outside 0 to count-1 TSE_GetSwing returns false with BAD INDEX.
TSE_EventCount and TSE_GetEvent
Stored events, newest at index 0: type, level (the swing price), swing_time, break_time (the bar that broke or swept it).
TSE_GetLevels
The newest swing high and swing low (0.0 if none yet) and whether each is already broken. An intact level is the next BOS or CHoCH trigger.
TSE_RangePosition
Where price sits between those two levels: 0 = swing low, 50 = equilibrium, 100 = swing high, below 0 or above 100 outside. price 0 = Bid of the handle's symbol. EMPTY_VALUE when a level is missing or high is not above low. The demo shows DISCOUNT below 45 and PREMIUM above 55.
TSE_ZoneCount and TSE_GetZone
Stored zones of every state, newest at index 0: kind, dir, top, bottom, time (FVG: middle candle; OB: the candle), state, fill 0-100.
TSE_NearestZone
Nearest FRESH or TESTED zone to price (0 = Bid); distance 0 inside a zone, ties go to the newer zone. kind: 0 any, 1 FVG, 2 OB. dir: 0 any, 1, -1. Returns its index for TSE_GetZone and fills top and bottom; -1 if none (error OK) or BAD PARAMETERS.
double top, bottom; int z = TSE_NearestZone(h, 2, 1, 0, top, bottom); // nearest bullish order block
TSE_GetStats
Pass a dynamic int array; it is resized to 12 and 12 is returned: 0 bars read, 1 swing highs, 2 swing lows, 3 BOS UP, 4 BOS DOWN, 5 CHOCH UP, 6 CHOCH DOWN, 7 SWEEP HIGH, 8 SWEEP LOW, 9 FVGs, 10 OBs, 11 zones active now. Counts since the last build.
TSE_LastError and the text functions
TSE_LastError: code of the last call. TSE_ErrorText, TSE_LabelText, TSE_EventText, TSE_ZoneText(kind, dir) and TSE_StateText return the strings listed under Codes.
Working Integration Example
#import "Tectonic_Structure_Engine.ex4"
int TSE_Create(string symbol, int timeframe, int strength, int history_bars);
void TSE_Release(int handle);
int TSE_Update(int handle);
int TSE_Trend(int handle);
bool TSE_GetEvent(int handle, int index, int &type, double &level, datetime &swing_time, datetime &break_time);
int TSE_NearestZone(int handle, int kind, int dir, double price, double &top, double &bottom);
string TSE_EventText(int type);
#import
int h = -1, htf = -1;
int OnInit()
{
h = TSE_Create("", 0, 3, 1000); // chart timeframe
htf = TSE_Create("", PERIOD_H4, 3, 1000); // higher-timeframe bias
return (h >= 0 && htf >= 0) ? INIT_SUCCEEDED : INIT_FAILED;
}
void OnDeinit(const int reason) { TSE_Release(h); TSE_Release(htf); }
void OnTick()
{
TSE_Update(htf);
int n = TSE_Update(h);
for(int i = n - 1; i >= 0; i--)
{
int type; double level; datetime st, bt;
if(TSE_GetEvent(h, i, type, level, st, bt))
Print(TSE_EventText(type), " at ", level, ", H4 trend ", TSE_Trend(htf));
}
double top, bottom;
if(n > 0 && TSE_NearestZone(h, 2, 1, 0, top, bottom) >= 0)
Print("nearest bullish OB ", bottom, " - ", top);
} Typical Setups
- Internal and external structure: two handles on one chart, strength 2 and 8.
- Multi-timeframe bias: chart handle for entries, H4 or D1 handle as a TSE_Trend filter.
- Wick breaks: TSE_Configure(h, 1, 0, 0.10, 0.25, 14); no sweeps in this mode.
- Fewer, larger zones and swings: fvg_min_atr 0.5-1.0, min_swing_atr 1.0.
Architecture and Notes
- One engine per handle, up to 32 handles per program; every importing program has its own. Data lives in memory and is rebuilt from history after a restart.
- Closed bars only, each read once, oldest first: nothing repaints and bar 0 is never used.
- Building 20,000 bars took about 80 ms in the MT4 Strategy Tester.
- Other symbols or timeframes are read with iHigh, iLow, iOpen, iClose and iTime; NO HISTORY is normal while the terminal downloads them. In the Strategy Tester use the tested symbol (any timeframe).
- Per handle: up to 2000 swings, 2000 events and 500 zones; the oldest 10% are dropped when full.
- MetaTrader 4 build 600 or later. Safe in the Strategy Tester and optimization. No DLLs, files, global variables, chart objects, timers, alerts or trading.
Risk Notice
The library describes price structure. It does not predict prices or guarantee profits. Test any strategy built on it on a demo account first.
