About
This template is an example and adds nothing of its own. The market structure elements are part of the engine's indicator catalogue: structure (BoS, CHoCH), fvg, ifvg, order_block, breaker_block, fib_retracement, fib_extension, premium_discount, ote, liquidity_sweep, equal_levels, liquidity, bpr, mitigation_block, rejection_block, displacement, killzones, midnight_open and opening_gaps. A strategy reads them one by one with ctx.ind("fvg", ...) or all nineteen at once with ctx.market_structure(...), Blocks offers them in the group Market structure, and the chart draws them when you add them as indicators. Their definitions, warm up and limits are on the indicator pages. That is the real implementation, and the one to use in a strategy.
What the template shows is how a plugin bundles catalogue elements in a plugin indicator. It sorts the parameters to the elements that take them with split from orionquant_engine.indicators.market (the function ctx.market_structure uses), builds each stream with get(id).make(**inputs), passes every bar to each stream in update(bar), and hands on each element's outputs as a read only reading, the way ctx.ind does. The parameters, their defaults and their bounds are read from the catalogue as well. The template finds no swing, measures no gap and computes nothing from prices: every value is the catalogue stream's own, so it is exactly what this reads at the same bar with the same inputs:
pythonms = ctx.market_structure(length=3)
if ms.trend == 1 and ms.premium_discount.zone == -1:
ctx.signal("LONG")Start here when a plugin of your own needs a catalogue indicator inside it, for example a filter of your own on top of the order blocks: build the stream the same way and keep your logic next to it.
Parameters
| Name | Type | Default | Range or options | Description |
|---|---|---|---|---|
length | int | 3 | min 1, max 50 | Swing bars on each side, for every element built on swings: structure, the order, breaker, mitigation and rejection blocks, both Fibonacci elements, premium_discount, ote, liquidity, liquidity_sweep and equal_levels. A swing is confirmed this many bars after its extreme. |
break_on | choice | "close" | close, wick | What breaks a swing in structure and the order, breaker and mitigation blocks: a close beyond it, or with wick a high or low beyond it. |
atr_length | int | 14 | min 1, max 500 | Bars in Wilder's ATR that sizes the gaps of fvg, ifvg, bpr and displacement, the body of a displacement and the tolerance of equal_levels. |
min_size | float | 0.25 | min 0, max 10 | The smallest gap that counts in fvg, ifvg, bpr and displacement, in multiples of the ATR at its third candle. 0 counts every gap. |
fill | choice | "full" | full, half | When a fair value gap counts as filled: full when price has passed through the whole gap, half at its middle (consequent encroachment). |
max_zones | int | 20 | min 1, max 500 | Zones or levels kept per side in every element that keeps them (the gaps, blocks, ranges and liquidity levels); past it the oldest goes without an event. |
zone | choice | "wick" | wick, body | What an order, breaker or mitigation block spans: wick for the full candle, body for its body only. |
tolerance | float | 0.1 | min 0, max 2 | How far apart two swing highs (or lows) may be and still count as equal in equal_levels, in multiples of the ATR. |
min_wick | float | 0.5 | min 0, max 1 | The smallest wick a rejection block counts, as a share of its candle's range. |
min_body | float | 1 | min 0, max 10 | The body a displacement candle needs: more than this many ATRs. |
days | choice | "mon_fri" | mon_fri, every_day | Which days killzones and midnight_open count: mon_fri for Monday to Friday, every_day for markets that trade at the weekend. |
Use it in a strategy
pythontk = ctx.plugin_indicator("market_structure_toolkit", "toolkit", {"length": 3})
if tk is not None and tk.value is not None:
# Trend up and the close inside the OTE zone of an up leg: long.
if tk.value == 1 and tk.ote.leg == 1 and tk.ote.inside == 1:
ctx.signal("LONG")
# A change of character down: out.
elif tk.structure.choch == -1:
ctx.signal("EXIT")The same strategy without the plugin reads ms = ctx.market_structure(length=3) and then ms.trend, ms.ote.leg, ms.ote.inside and ms.choch, with the same values at every bar. That form also runs in Blocks, Rust and C# and reaches the exports; the plugin form runs in Python strategies only.
What it provides
valueValue | The trend of the structure element: 1 up, -1 down, 0 before the first break. None while it warms up. |
structureValue | The reading of `structure`: trend, bos, choch, swing_high, swing_low, bos_level and choch_level. |
fvgValue | The reading of `fvg`: bull_top, bull_bottom, bear_top, bear_bottom of the nearest open gaps, bull_new, bear_new, bull_filled and bear_filled. |
ifvgValue | The reading of `ifvg`: the same zone lines as fvg, with bull_broken and bear_broken. |
order_blockValue | The reading of `order_block`: the zone lines of the nearest blocks, the new flags, bull_broken and bear_broken. |
breaker_blockValue | The reading of `breaker_block`: the same lines as order_block, for broken blocks kept as zones of the other side. |
fibValue | The reading of `fib_retracement`: level_0, level_236, level_382, level_500, level_618, level_786, level_1000 and leg. |
fib_extensionValue | The reading of `fib_extension`: level_1272, level_1618, level_2000, level_2618 and leg. |
premium_discountValue | The reading of `premium_discount`: equilibrium, range_high, range_low and zone (1 premium, -1 discount). |
oteValue | The reading of `ote`: top, bottom, inside and leg of the 0.62 to 0.79 retracement zone. |
liquidity_sweepValue | The reading of `liquidity_sweep`: up and down on the bar of a sweep, up_level and down_level the last swept prices. |
equal_levelsValue | The reading of `equal_levels`: eqh and eql, the nearest pools of equal highs and lows, with their new and taken flags. |
liquidityValue | The reading of `liquidity`: buy_side and sell_side, the nearest untaken swing high and low, with buy_taken and sell_taken. |
bprValue | The reading of `bpr`: the zone lines of the nearest balanced price ranges, the new flags, bull_broken and bear_broken. |
mitigation_blockValue | The reading of `mitigation_block`: the same lines as order_block, for the swing candle a failure swing broke. |
rejection_blockValue | The reading of `rejection_block`: the same lines as order_block, for the long wicks at swing highs and lows. |
displacementValue | The reading of `displacement`: up, down, and high, low and body_atr of the last displacement candle. |
killzonesValue | The reading of `killzones`: asia, london_open, new_york_open and london_close, each with its high and low. |
midnight_openValue | The reading of `midnight_open`: open, position (1 above, -1 below) and first_bar. |
opening_gapsValue | The reading of `opening_gaps`: top, bottom and filled of the new week gap (nwog) and the new day gap (ndog). |
When values are known
Every value is known when the catalogue element knows it, at the close of the bar, exactly as ctx.ind gives it: a swing length bars after its extreme, a gap on its third candle. Nothing reported changes with later bars. Each reading is a snapshot: keeping one past its bar keeps the values it had. Warm up is each element's own; an output is None until its element has something to show.
Limits
- An example only: it adds nothing to the catalogue elements, and in a strategy
ctx.market_structureorctx.indis shorter and does the same. - One set of parameters for all nineteen elements; for a different length per element, read each one with
ctx.ind. - The definitions belong to the catalogue: a change there reaches this plugin without a new version of it.
- A plugin indicator is not drawn on the chart and is not available in Blocks, Pine, Rust or C#; it runs on the run's own instrument only. The catalogue elements themselves are.