Block Reference
Complete reference for all 100 blocks the engine runs: the 98 the editor offers, plus two retired ones kept so a saved graph still loads. Every block has a strongly-typed socket system: Number, , Boolean, DateTime. Invalid connections are rejected before you run.
Blocks marked tunable can be exposed to PSO optimization. All indicators are computed on closed bars only, so there is no lookahead bias.
Naming a block. Right-click any block on the canvas for
Name this block, Duplicate, Delete and a link
straight to that block’s entry below. Without a name a block is identified by the
automatic id it was given when you added it (n3,
n7, …), and that id is what Optimize and Sensitivity show
on their axes, so two blocks of the same type read as
n3.period and n7.period. Naming them turns those
labels into Fast EMA.period and
Slow EMA.period. A name is a label only: it never changes a
result, no two blocks in one strategy may share one, and it may not contain a
dot, because the labels are name.parameter. Clearing a name
brings the automatic id back.
Source
Raw data inputs: bar prices, tick prices, position state, time constants. Source blocks have no inputs.
Source.Bar.Current instead.Gate.Session takes a , and no block in the catalog declares a DateTime input at all; the connection validator refuses DateTime → Number. For a time-of-day window use Gate.Session, which is the one clock in the graph that follows CET/CEST, and whose four hour and minute parameters can be handed to the optimizer. The block is kept here and in the catalog so a graph saved with one still loads and still says what it is.number default 0tunableSource.Time.Now this block was designed for could never be wired, and the two are on different scales in any case, one an absolute instant and one a time of day. For a time-of-day window use Gate.Session. The block is kept here and in the catalog so a graph saved with one still loads and still says what it is.integer 0–23, default 9integer 0–59, default 0boolean default truetimestamp gives the bar’s epoch time in milliseconds, always the START of the bar’s period, so an M15 bar reading 09:00 covers 09:00 up to 09:15 whatever time its first tick arrived.enum open | high | low | close | volume | bid | ask | timestamp, default closeCompare.GTE for time-based exits.HighSinceEntry − (ATR × mult) → Sink.UpdateStop for a trailing stop on longs that follows the high since entry. A chandelier stop over the last N bars uses the lower of this and the high of those N bars.LowSinceEntry + (ATR × mult) → trailing stop.Math.Max(PositionStopLoss, newTrail) prevents the stop moving away.Source.PositionStopLoss, it does not move when the stop trails, so it stays usable as a reference after the stop has been moved. Returns 0 when flat, and also 0 when no initial stop was recorded, so treat 0 as unknown rather than as no risk.close − entry for longs, entry − close for shorts. Returns 0 when flat. Use with Compare.GT to gate trailing stop activation (e.g. only trail after +20 pts profit).Aggregator
Timeframe resampling. All aggregators emit the last fully closed bar: no bar that is still forming, no lookahead. A bar is held stable until the next one closes. The first bar after the data starts can cover only part of its period, and the bar-fed aggregators do not fill gaps: a period without base bars produces no bar. The TickToBar aggregators set a bar’s volume to the number of ticks in it.
Levels hold, events fire once. While a higher-timeframe bar is still forming, the aggregator re-emits the last completed one on every base bar, and downstream blocks hold their state. For a level that is what you want: an Indicator.EMA behind an Aggregator.M5 keeps reading the same value across all five M1 bars. An event is different: a candlestick or chart pattern, or Indicator.SwingHigh’s confirmed, is a statement about one completed bar, so it is reported on the single base bar that carries that bar and reads false on the rest of the period. One pattern occurrence is one trigger, whatever timeframe it sits behind. ready is a level, not an event, and stays true in between.
Quiet periods are filled, long gaps are not filled completely. When no tick arrives for one or more whole periods (a lunch lull, an overnight break, a weekend), a TickToBar aggregator emits a synthetic bar for each skipped period, flat at the last traded price with volume 0, so downstream rolling windows keep advancing instead of jumping. Synthetic bars are capped at 500 per gap: a weekend on Aggregator.TickToBar.M1 is about 2880 skipped minutes, so the series steps forward in time once the cap is reached. Zero volume is the reliable way to tell a synthetic bar from a real one that happened to trade flat. Filler is also truncated if trading resumes faster than the aggregator can publish it (one bar leaves per incoming tick), because a real bar always takes precedence over leftover filler. Real bars are never dropped, and the ticks that arrive during filling are counted in the bar they belong to.
Where a day starts, and why there is more than one answer. The product uses two day boundaries, deliberately, and they are one hour apart:
- The UTC grid, 00:00 UTC. A dataset you convert yourself, the bars the chart
draws, and the engine’s own tick→bar loop all bucket on
floor(t / period). They share it on purpose: it is what makes a chart, a converted file and a backtest of that file show the same bar, and it is reproducible from a timestamp alone with no timezone database. - A fixed UTC+1, 23:00→23:00 UTC. The graph blocks
Aggregator.D1andAggregator.TickToBar.D1key the day this way, and so doIndicator.VWAP’s daily reset andIndicator.PivotPoints. It is midnight in the market this platform was built for, but it is a fixed hour all year, so the day starts at midnight Berlin time in winter and at 01:00 Berlin time in summer.
So a D1 bar inside a graph and a D1 bar on the chart are not the same bar, and neither
of them starts the day at local midnight through the summer. Gate.Session is the exception: it
is the only clock in the graph that follows CET/CEST, so within one graph a session window and an
Aggregator.D1 bar disagree about when a day begins for half the year. Both rules are kept
rather than unified, because changing either one silently moves every saved D1 strategy’s results;
this paragraph is here so the difference is visible instead of discovered.
Several timeframes in one graph. A graph can use
any number of aggregators side by side, each fed from the base bar or from another aggregator (a chain), and
each keeps its own state: two aggregators of the same period on the same input publish the same bars. A
higher-timeframe bar becomes visible on the base bar whose end reaches the bar’s end. An M15 bar from
10:00 to 10:15 is first seen by the decision made on the M1 bar 10:14, and an entry that decision triggers
fills on the next base bar. A chain Aggregator.M15 → Aggregator.M60 publishes
the same hourly bars as a direct Aggregator.M60. When a gap in the data closes two periods on
one base bar, both are published in order, so an indicator behind the aggregator counts each of them once.
Indicators behind an aggregator warm up in its bars: an Indicator.EMA with period 3 behind
Aggregator.D1 needs three completed days. Source.BarsSinceEntry counts base bars,
not aggregated ones.
The period must fit the bars it receives. An aggregator’s period
must be a whole multiple of the bars it receives, from the dataset or from the aggregator in front of it.
The engine builds a higher-timeframe bar from whole input bars, so an Aggregator.M15 on M10 bars
would build bars of 20 and 10 minutes, and an Aggregator.M5 on M15 bars cannot split them and
would pass every M15 bar through. A run with such a graph is refused with a message that names the block.
An aggregator equal to its input passes the bars through unchanged and is allowed.
Diagnostic Mode builds its bars differently again. A diagnostic aggregates your data to the timeframe you pick by anchoring buckets on the dataset’s session open and discarding any bucket that did not receive a full set of base bars, and it refuses H4 and D1 outright because the daily maintenance break leaves those permanently short. That is a different analytical lens on purpose (it isolates exit mechanics), and it means diagnostic numbers are not meant to be compared like-for-like with a backtest of the same strategy on the same data.
Source.Tick.Price → mid into price, then feed bar output to indicators. Only available in tick-data mode.Indicator.EMA for a clean daily-trend filter.Aggregator.TickToBar.M1 builds M1 bars: a period closes when a tick arrives whose timestamp falls into the next 15-minute slot, so everything downstream reads a CLOSED bar. Only usable when the graph timeframe is TICKS.Aggregator.TickToBar.M1 builds M1 bars: a period closes when a tick arrives whose timestamp falls into the next 30-minute slot, so everything downstream reads a CLOSED bar. Only usable when the graph timeframe is TICKS.Aggregator.TickToBar.M1 builds M1 bars: a period closes when a tick arrives whose timestamp falls into the next 60-minute slot, so everything downstream reads a CLOSED bar. Only usable when the graph timeframe is TICKS.Aggregator.TickToBar.M1 builds M1 bars: a period closes when a tick arrives whose timestamp falls into the next day (days run 23:00–23:00 UTC, see the note above), so everything downstream reads a CLOSED bar. Only usable when the graph timeframe is TICKS.Indicator
Technical indicators computed on closed-bar data. Until enough history exists, ready is false and the value is a placeholder: 0 for most blocks, 50 for RSI and Stochastic, the average of the partly filled window for SMA, and the current bar’s own field for Highest/Lowest. Gate on ready, not on the value. Formulas shown use standard notation: N = period, t = current bar.
value only once this is trueinteger 2–500, default 20tunablevalue only once this is trueinteger 2–500, default 20tunablevalue only once this is trueinteger 2–500, default 20tunableenum open | high | low | close, default closevalue only once this is trueinteger 2–500, default 20tunableenum open | high | low | close, default closevalue only once this is trueinteger 2–500, default 20tunableenum open | high | low | close, default closevalue only once this is trueinteger 2–500, default 20tunableenum open | high | low | close, default closevalue only once this is trueinteger 2–200, default 14tunablevalue only once this is trueinteger 2–100, default 14tunableperiod+1 bars, earlier than value, which needs about 2×period barsperiod DX values on top of the warmup, so later than +DI/−DIinteger 2–100, default 14tunableperiod bars have been seeninteger 2–200, default 20tunableMath.CrossesAbove / Math.CrossesBelow against a constant 0. The cross only counts once this block has warmed up, so what it reads while warming up is never taken for a crossing.period bars have been seeninteger 2–200, default 14tunablePARABOLIC_SAR exit strategy, which is anchored on a single trade’s entry and only exits; this one runs continuously and reverses.acceleration, steps by it on each new extreme,
and is capped at maximum
The SAR never reaches into the previous two bars’ range.
On penetration it jumps to the prior EP (not to the current
price), AF resets, and the side flips.number 0.001–0.5, default 0.02tunablenumber 0.01–1.0, default 0.2tunable if set below acceleration it is raised to acceleration, so AF never stepsIndicator.ROC instead when you want the same move as a percentage. A fixed momentum threshold means something different at different price levels.period+1 closes have been seen, because a lookback of N bars needs N+1 closesinteger 1–200, default 10tunableMath.CrossesAbove / Math.CrossesBelow against a constant 0. The cross only counts once this block has warmed up, so what it reads while warming up is never taken for a crossing.Indicator.Momentum, expressed as a percentage of where price was. The denominator is the old close, not the current one, so the reading answers “how far has it come from there” and stays comparable across price levels.period+1 closes have been seeninteger 1–200, default 10tunableperiod, ROC is exactly 0 on every ready bar, because the lookback lands on the same phase every time.Math.CrossesAbove / Math.CrossesBelow against a constant 0. The cross only counts once this block has warmed up, so what it reads while warming up is never taken for a crossing.volume field, and the datasets this platform works with carry no traded volume: on bar files that field holds the bar’s range, on bars built from ticks by an Aggregator.TickToBar block it holds the number of ticks. So this is a range- or activity-weighted average, not a volume-weighted one. On the first bar of a session it equals that bar’s close.value only once this is truek and d only once this is true (both read 50 before then; k is also 50 when the range has zero width)integer 2–100, default 14tunableinteger 1–50, default 3tunableperiod bars have been seen; read the bands only once this is true (all three read 0 before)integer 2–500, default 20tunablenumber 0.1–5.0, default 2.0tunableclose > Highest(N) can actually be true). Use for Donchian-style breakout levels or resistance detection.value only once this is trueinteger 2–500, default 20tunableenum open|high|low|close, default highclose < Lowest(N) is true when the close is below that minimum.value only once this is trueinteger 2–500, default 20tunableenum open|high|low|close, default lowinteger 1–50, default 5tunableinteger 1–50, default 5tunableinteger 2–200, default 12tunableinteger 5–500, default 26tunableinteger 2–100, default 9tunableMath.CrossesAbove(macd, signal) for signal-line crosses, and Math.CrossesAbove(histogram, 0) / Math.CrossesBelow(histogram, 0) for a histogram sign change. Neither fires before MACD has warmed up, even though MACD has no ready port of its own.integer 2–500, default 20tunablemult × ATR. The width follows the Average True Range, where Bollinger Bands follow the standard deviation of the close; whether the Bollinger Bands lie inside the channel is a condition you can wire with Compare blocks.integer 2–500, default 20tunableinteger 2–200, default 14tunablenumber 0.1–10.0, default 2.0tunableinteger 2–500, default 20tunableMath.CrossesAbove / Math.CrossesBelow against a constant 0. Z-Score reads 0 while it warms up and has no ready port, but the cross still waits until it is warmed up.merge_zone_pts of an existing pivot level is merged into it; session, previous-day, overnight, weekly, opening-range and round-number levels are not merged. Proximity gates use ATR multiples to define the "touch zone". All clock times are a fixed UTC+1 (no daylight saving), and the overnight window always opens at 22:00. If atr_value is not wired, 1.0 price unit is used as the ATR. A pivot level is discarded once a close breaks it by 0.3 × ATR.integer 3–50, default 10tunablenumber 0.1–2.0, default 0.5tunablenumber 1–50, default 5tunablenumber 10–1000, default 100tunableinteger 0–23, default 8tunableinteger 0–59, default 0tunableinteger 5–120, default 30tunableinteger 0–12, default 9tunablepullback_min_atr ATRs. If either phase lasts longer than max_bars_between bars, counting starts again. Wire a SupportResistance.support price into level.boolean default truenumber 0.1–3.0, default 0.5tunableinteger 3–100, default 20tunablebreak_atr_mult × ATR. Once broken, is_breakout stays true until a retest is detected, max_retest_bars expires, or a close back beyond the level by break_atr_mult × ATR cancels the break. A break that fired or expired cannot re-arm in the same direction until price has come back inside that threshold. A level of 0 is treated as a real level, so gate the input when no level exists. Retesting the broken level from the new side fires is_retest_long or is_retest_short once.number 0.1–2.0, default 0.3tunablenumber 0.1–2.0, default 0.5tunableinteger 3–60, default 15tunablebody_ratio of its rangenumber 0.001–0.5, default 0.1tunableGate.TrendGate or an EMA comparison to supply that context. All three thresholds are fractions of the bar’s range, and since range = body + upper + lower, the defaults 0.6 / 0.3 / 0.1 form one partition of the range rather than three unrelated numbers. They also imply the textbook “lower shadow at least twice the body” without ever dividing by a body, which can be zero.number 0.3–0.95, default 0.6tunablenumber 0.01–0.6, default 0.3tunablenumber 0.0–0.4, default 0.1tunableopen[t] equals close[t−1] on essentially every bar, so the textbook’s strict “opens beyond the previous close” would make bullish engulfing almost undetectable; the strict bound is kept where the pattern’s actual claim lives, on the close. The previous bar is guaranteed a non-zero body by the colour test, so the classic “everything engulfs a doji” false positive cannot arise.number 0.1–0.9, default 0.5tunablenumber 0.05–1.0, default 0.5tunablenumber 0.1–0.9, default 0.5tunableIndicator.SwingHigh / SwingLow.
Every tolerance is a fraction of the pattern’s own height (the distance from the peaks down to the trough between them), never of price and never of ATR. A pattern twice as tall is allowed twice the absolute discrepancy between its peaks, because it looks the same. That makes one default work across instruments, timeframes and pattern sizes alike. If you want a minimum size filter as well, compose one from
Indicator.ATR: that is a volatility question, not a shape question, and folding it in here would give the block a second hidden time scale.
It fires on the breakout close, not when the shape completes. The second pivot is only confirmed
lookback bars after the fact, so firing there would be both late and untradeable. A close-based break is also immune to the single-wick false break that a high/low-based one is not. The pattern is discarded unfired if price closes beyond the two extremes first, if the confirmation window expires, or if a new pivot changes the skeleton.integer 1–50, default 5tunablenumber 0.01–0.5, default 0.1tunablenumber 1.0–10.0, default 3.0tunablenumber 0.1–5.0, default 1.0tunableneckline_tolerance only bounds how steep the fit may get before the shape stops being a head and shoulders at all. It is looser than price_tolerance for exactly that reason: a sloping neckline is normal, asymmetric shoulders are not.
Note that
price_tolerance works in both directions: the shoulders must be within it of each other, and the head must stand clear of them by more than it. One threshold defines what “indistinguishable” means; the shoulders must be it and the head must not.integer 1–50, default 5tunablenumber 0.01–0.5, default 0.1tunablenumber 0.01–1.0, default 0.25tunablenumber 0.1–5.0, default 1.0tunableThe break levels are horizontal: the upper one is the higher of the two swing highs, the lower one the lower of the two swing lows, both fixed when the shape is recognised, not the sloping trendlines. A symmetrical triangle therefore breaks only on a close beyond its outermost pivot.
This is the one pattern block with more than two signal outputs. The three shape ports are true on each completed bar while the shape is armed (behind an aggregator: only on the evaluation that completes a bar), so a graph can gate on “a triangle is forming” separately from the break. An ascending triangle that breaks downward is a failure worth reacting to, and the direction ports alone cannot express that. The tolerance is a fraction of the triangle’s own span.
integer 1–50, default 5tunablenumber 0.01–0.5, default 0.1tunablenumber 0.1–5.0, default 1.0tunablepole_ratio is the pole’s height as a multiple of the consolidation’s own height. That ratio is the visual definition of a flag, and it is self-relative like every other threshold here. max_retracement caps how much of the pole the pullback may give back; deeper than that is a reversal candidate, not a continuation, and the two should not share a signal.
The default
lookback is 3 rather than 5 because a flag’s consolidation is short by definition, and a 5-bar fractal often cannot resolve two pivots inside one.integer 1–50, default 3tunablenumber 1.0–10.0, default 2.0tunablenumber 0.05–0.95, default 0.5tunablenumber 0.1–5.0, default 1.0tunableGate
Filters that block or allow entry based on time, trend, volatility, or regime. Wire Gate outputs into Logic.And with your entry conditions. While warming up, Trend Gate and Volatility Gate allow entries, HMM Regime and Regime Cluster block them (allow = false), and Regime Filter reports NEUTRAL.
start ≤ t < end), and a start after the end means an overnight session. This is the only daily clock in the graph that follows CET/CEST: Aggregator.D1, Indicator.VWAP and Indicator.PivotPoints key their day on a fixed UTC+1 all year (see the note under the Aggregators). All four hour and minute parameters can be marked tunable and searched by PSO, which is how a session start is optimized rather than guessed.integer 0–23, default 7tunableinteger 0–59, default 0tunableinteger 0–23, default 20tunableinteger 0–59, default 0tunableboolean default true false evaluates the window in UTCblock_long_below_slope). The slope output is available for further gating or plotting.integer 5–500, default 50tunableinteger 2–200, default 14tunableinteger 2–200, default 12tunablenumber −5.0–5.0, default −0.5tunableinteger 2–200, default 14tunableinteger 100–20000, default 2000tunablenumber 0.0–1.0, default 0.80tunableinteger 2–200, default 20tunableinteger 5–500, default 50tunableinteger 2–200, default 14tunableinteger 2–200, default 10tunableinteger 1–200, default 10tunablenumber 0–5, default 0.0081tunablenumber 0–5, default 0.0254tunablenumber 0–5, default 0.0017tunablenumber 0–1, default 0.4tunablenumber 0–5, default 0.5tunableinteger 2–200, default 20tunablenumber 0–3, default 0.79tunablenumber 0–3, default 0.64tunableinteger 2–5, default 3integer 2–500, default 10boolean default false; adds the bar’s volume relative to its rolling mean as an observationboolean default false; adds the bar’s range, (high − low) / close, as an observationinteger 1–50, default 5integer 10–2000, default 200integer default 42integer 0–(n_states−1), default 0number 0.0–1.0, default 0.50adx_period) and the lag-1 autocorrelation of log returns, which separates mean-reverting from momentum character. No volume: the bar datasets do not reliably carry one. Inside a walk-forward run the block is fitted with k-means on every block's in-sample window; the number of clusters is chosen automatically by silhouette score over the fixed range 2–6, counting only partitions whose smallest cluster holds at least 5% of the window, because a handful of transition bars after a regime switch is not a regime of its own. If no cluster count meets that rule, the most balanced partition is kept and the walk-forward overview flags it. Each feature is weighted by how clearly its values fall into groups, beyond what random noise would show, so a feature that is only noise does not steer the clusters; the weights are shown per block in the walk-forward overview. Each bar is then assigned to the nearest cluster using only that bar's own features, which makes it causal by construction. The next block refits from scratch. Clusters are numbered by ascending volatility centroid, so cluster 0 is the calmest cluster after every refit. Only cluster 0 keeps that meaning across blocks: the count is chosen again for every block, so cluster 2 in one block need not be the same regime as cluster 2 in the next. The is_cluster_k outputs at or beyond the fitted count read false. A cluster is described only by its measured feature means (mean volatility, mean trend strength, mean autocorrelation of its bars); nothing ranks one cluster against another. Usable in walk-forward runs, and in a backtest with an in-sample split (fitted on the in-sample part) or one that is handed the walk-forward block's own model (Block Detail). A backtest with neither refuses the graph, and so do Optimize and the parameter sweep, and so does a gate_cluster the fit did not find: the run is refused rather than silently never allowing. While ready is false, allow and every is_cluster_k are false, cluster is −1 and the feature outputs read 0: gate on ready.integer 2–200, default 14integer 2–200, default 14integer 5–500, default 20integer 0–5, default 0; must be below the fitted cluster countinteger 1–50, default 5integer 10–1000, default 100integer default 42Compare
Numeric comparison operators. Two Number inputs → one Boolean output. No parameters except Compare.EQ which has an epsilon tolerance.
| Block | Type | Logic | Notes |
|---|---|---|---|
| a > b | Compare.GT | true if a > b | strict, no tolerance |
| a ≥ b | Compare.GTE | true if a ≥ b | |
| a < b | Compare.LT | true if a < b | strict |
| a ≤ b | Compare.LTE | true if a ≤ b | |
| a ≈ b | Compare.EQ | |a − b| ≤ ε | param epsilon default 1e-9 |
All compare blocks have two Number inputs named a and b, and one Boolean output named value.
Logic
Boolean logic gates for combining conditions. AND/OR/NOT have no parameters. IF-THEN-ELSE bridges Boolean conditions into numeric values.
| Block | Type | Inputs | Output | Logic |
|---|---|---|---|---|
| AND | Logic.And | a, b (Boolean) | Boolean | a AND b |
| OR | Logic.Or | a, b (Boolean) | Boolean | a OR b |
| NOT | Logic.Not | a (Boolean) | Boolean | NOT a |
| IF-THEN-ELSE | Logic.IfThenElse | condition (Bool), value_if_true, value_if_false (Number) | Number, output port result | condition ? a : b |
Use Logic.And to combine gate conditions (session AND regime AND entry condition). Use Logic.IfThenElse to select between two stop distances based on a condition, or implement a breakeven guard.
Math
Arithmetic operations on Number streams. Most have two Number inputs and one Number output. Crossover blocks output Boolean. Rolling blocks operate over a history window.
| Block | Type | Formula / Notes |
|---|---|---|
| a + b | Math.Add | value = a + b |
| a − b | Math.Sub | value = a − b. Use: HighSinceEntry − ATR×mult for trailing |
| a × b | Math.Mul | value = a × b. Use: ATR × constant for dynamic SL sizing |
| a ÷ b | Math.Div | value = a / b. Returns 0 if |b| ≤ 1e-12 (prevents NaN) |
| |a| | Math.Abs | value = |a|. Single input. |
| min(a,b) | Math.Min | value = min(a, b) |
| max(a,b) | Math.Max | value = max(a, b). Use: max(PositionStopLoss, newTrail) to only tighten |
| a crosses above b | Math.CrossesAbove | true only on the bar where a transitions from ≤ b to > b (prev_a ≤ prev_b AND a > b) |
| a crosses below b | Math.CrossesBelow | true only on the bar where a transitions from ≥ b to < b. Both blocks fire only between two samples on which every warming-up block feeding them (indicators, Math.Lag, gates, also through other Math blocks) was ready, so a warm-up reading is never taken for a crossing. A constant has no warm-up, so a cross against 0 is an ordinary cross. A 0 read directly from an output where 0 means “no level” (a swing price before the first swing, a support or resistance that does not exist, broken_level with no live break) counts as missing. |
| Rolling SMA | Math.RollingSMA | SMA of upstream Number stream over param period (2–1000, default 20)tunable. E.g. SMA(ATR, 50). Outputs value (Number) and ready (Boolean, false until the window is full); before that, value is the average of the samples seen so far. |
| Lag(N) | Math.Lag | Returns value from N bars ago (param period 1–500, default 1). Returns 0 until N+1 values seen. Input/output: Number Outputs value (Number) and ready (Boolean, false until N+1 values have streamed). |
| LagBar(N) | Math.LagBar | Returns the upstream from N completed higher-timeframe bars ago. Advances only when bar.timestamp changes. It counts completed bars from any upstream Aggregator (D1, M60, M30, M15, M5, M1) regardless of the graph's base timeframe. An aggregator already publishes the last completed bar, so Aggregator.D1 → Bar.Field(high) is yesterday's high; Aggregator.D1 → LagBar(1) → Bar.Field(high) is the day before yesterday, and LagBar(N) is N completed days before the last completed one. Returns no bar until N+1 distinct bars seen. |
| Custom formula | Math.Formula | Your own calculation over inputs you declare on the block: each input has a name and a type (Number or Boolean, at most 16), the one output likewise, and the formula is written over the input names. Operators: + - * / % ^ (^ is the power, right-associative, and binds tighter than a sign: -2^2 is −4), comparisons < <= > >= == != (not chained; == on numbers is exact), and or not (also && || !) and a conditional c ? a : b or if(c, a, b). Functions: abs sqrt floor ceil round sign exp log min max pow clamp (round is half away from zero, log is natural, clamp(x, lo, hi) = min(max(x, lo), hi)). Nothing else exists: no loops, no text, no names other than the inputs. The formula is checked when the graph is saved and again when a run starts; one that does not compile refuses the graph, and every declared input must be connected. Stateless: the same inputs always give the same value. A result that is not a finite number (division by zero, the square root of a negative number, log of zero) publishes no value on that bar rather than 0; b == 0 ? 0 : a / b is the guard, and ? :, if, and, or evaluate only the side they need. Example: inputs high, low, close; formula (high - low) / close * 100, the bar’s range in percent. |
The Math.CrossesAbove / Math.CrossesBelow blocks output Boolean. Math.LagBar takes a input and outputs a . All other Math blocks take and output Number. RollingSMA and Lag take a single input named value; all others take a (and b where applicable).
Sink
Output blocks that interact with the position manager. Sinks have no outputs; they cause side effects (opening positions, closing them, moving stops).
string default "graph_long"; the label this entry records on its trade, shown next to the exit reason in the trade list (plain text, at most 64 characters, control characters removed); it never changes the fillnumber default 1.0: position size in units; must be greater than 0string default "graph_short"; the label this entry records on its trade, shown next to the exit reason in the trade list (plain text, at most 64 characters, control characters removed); it never changes the fillnumber default 1.0: position size in units; must be greater than 0all, oldest, newest, or by_id. There is no default: a graph that does not state a target will not load, because "close the position" is ambiguous the moment two are open. side_filter narrows the candidates first, so target=oldest with side_filter=SHORT closes the oldest short. An exit fills at the close of the bar it fires on, minus spread and slippage, unlike an entry, which fills at the next bar’s open.target=by_id; names the position to closeenum all | oldest | newest | by_id; no default, must be setenum ANY | LONG | SHORT, default ANYstring default "graph_exit"; a label recorded on the trade; a graph exit is always priced as a market exit, whatever it is callednumber default 1: the share of each chosen position to close. 1 closes it outright; 0.5 closes half and leaves the rest open with its stop-loss and take-profit unchanged. The share is of the position's current size, so two exits of 0.5 leave a quarter. Each share closed appears as its own trade, with its own P&L.tunablenumber default 0. When a partial close would leave less than this size, the whole position closes instead. Use it for the smallest position you can actually hold (for example, one minimum lot). 0 never closes the rest early.tunabletarget=by_id; names the position whose stop movesenum all | oldest | newest | by_id, default allenum ANY | LONG | SHORT, default ANYNote
An annotation on the canvas. It has no sockets and one parameter, its text, and the engine does not evaluate it. A strategy computes exactly the same trades with or without one.
text default empty; the block is not evaluated