TradingView indicator guide

HalfTrend indicator: verify the state change before trusting the arrow

The HalfTrend indicator tracks a persistent trend state using rolling highs, lows and their moving averages. In the public everget implementation, Amplitude controls those price windows; Channel Deviation changes the ATR envelope, not the reversal test. An arrow on an open candle can disappear before the close. Verify the exact source version, then compare completed-bar states and alert timestamps.

See the decision guide

Identify the public implementation and its inputs

This guide follows everget's public HalfTrend source, pinned to repository commit 942448df1864af35373488a4b732bba5a531d0a7. The TradingView publication identifies its trend logic as different from SuperTrend. Compare the source behind the actual chart instance before assuming that another HalfTrend, a paid variant or a strategy conversion matches it.

  • A larger Amplitude changes the reversal calculation. It is not a guaranteed noise filter or a universally better setting.
  • For an unchanged price history, changing Channel Deviation changes band placement but leaves the trend-state transitions unchanged. Do not optimize it as though it directly changes the original buy/sell conditions.
  • The pinned repository source carries GPL-3.0 terms. Preserve its attribution and license when adapting or redistributing it; a script being publicly readable does not remove its reuse conditions.
SettingReference defaultWhat it changes
Amplitude2 chart barsThe highest high, lowest low, SMA of highs and SMA of lows used by the state machine.
Channel Deviation2Half-width = deviation × ATR(100) / 2 around the active HalfTrend line.
ATR length100 in the sourceThe envelope and marker availability; it is not the Amplitude input.
Show arrows / channels / labelsDisplay controlsVisibility only; hiding an arrow does not disable an alert condition.

Follow the state machine, including its initialization

The reference starts with trend = 0 and nextTrend = 0, remembered low/high values taken from the previous bar or the first bar, and up/down lines initialized to zero. State 0 selects the up line; state 1 selects the down line. The initial state is a seed, not a buy signal. Matching only the latest Amplitude bars is insufficient because the remembered extrema persist across bars.

  • Equality does not satisfy either strict comparison. Both tests must hold on the same calculation.
  • Within an up phase, the up line ratchets upward with maxLowPrice. Within a down phase, the down line ratchets downward with minHighPrice. At a reversal, the new active line inherits the previous opposite line.
  • Use identical loaded history and allow ATR to initialize when comparing implementations. The reference requires an available ATR-derived arrow value before its buy/sell condition is true; a state change during warm-up need not produce a marker.
Branch being evaluatedMemory updateRequired reversal tests
nextTrend = 1Raise maxLowPrice to max(previous memory, lowest low over Amplitude).SMA(high, Amplitude) < maxLowPrice AND close < previous low: set trend = 1, nextTrend = 0 and minHighPrice = rolling highest high.
nextTrend = 0Lower minHighPrice to min(previous memory, highest high over Amplitude).SMA(low, Amplitude) > minHighPrice AND close > previous high: set trend = 0, nextTrend = 1 and maxLowPrice = rolling lowest low.

Recalculate a sideways sequence one bar at a time

These are hypothetical completed candles, not a backtest. Use Amplitude = 2 and assume warmed-up ATR. Start after bar A with trend = 0, nextTrend = 1, maxLowPrice = 100 and up = 100. A has high 101, low 100 and close 100.5. This explicit seed isolates the following transitions; it does not claim that loading only these seven bars reproduces a full chart.

  • At D, rolling highest high is max(99.4, 99.2) = 99.4. That initializes minHighPrice for the down phase. The new down line inherits 100 from the prior up line before ratcheting to 99.4 at E.
  • At G, assume ATR(100) = 2.4. Half-ATR is 1.2. With Channel Deviation = 2, the half-width is 2.4 and the bands are 99.4 + 2.4 = 101.8 and 99.4 - 2.4 = 97.0. Deviation = 3 would move them to 103.0 and 95.8 without moving the flip.
  • If a hypothetical short were filled at D close 98.7 and covered at G close 100.5, one unit of the instrument would lose 1.8 price units before costs, excluding any contract multiplier. Those assumed same-close fills are not demonstrated by the indicator. The example shows how two valid confirmed reversals can still whipsaw in a range.
BarHigh / low / closeAverage and threshold testFinal state / line
B99.8 / 99.0 / 99.2High SMA = 100.4; not below remembered low 100.Up / 100
C99.4 / 98.8 / 99.0High SMA = 99.6 < 100, but close 99.0 equals previous low 99.0.Up / 100
D99.2 / 98.5 / 98.7High SMA = 99.3 < 100 AND 98.7 < previous low 98.8.Down / 100; sell flip
E100.0 / 99.0 / 99.8Low SMA = 98.75; not above remembered high 99.4.Down / 99.4
F100.4 / 99.6 / 100.2Low SMA = 99.3; not above remembered high 99.4.Down / 99.4
G100.6 / 100.0 / 100.5Low SMA = 99.8 > 99.4 AND 100.5 > previous high 100.4.Up / 99.4; buy flip

Compare the live candle with the historical result

On the open D candle, suppose high is 99.2, low is 98.5 and the latest price is 98.7. The sell test is temporarily true. If that same candle closes at 99.0 instead, its high SMA remains 99.3 but its close is no longer below C low 98.8. The historical calculation has no D sell flip. That is a different final D candle from the table above.

  • Pine indicators recalculate on realtime updates. Ordinary persistent variables roll back to the previous committed bar state before each update; an early provisional flip is not automatically carried into the final calculation.
  • Record each live candidate with candle time, observed price, high/low, state and confirmation status. At the close, record the final state and marker. Reload with the same settings and compare that completed candle with the saved close record.
  • Compare historical candles sequentially and include a strict-equality case, a rejected first test, a rejected second test and a reversal in each direction. Bar Replay is useful for completed-bar comparison, but historical OHLC cannot reconstruct every live tick.
  • A mismatch after reload needs investigation of source version, history start, feed, session, chart type and inputs. Higher-timeframe adaptations require separate confirmation rules; this example uses only the chart timeframe.

Pine Script v6: keep the state calculation and confirm the alerts

This GPL-3.0 adaptation preserves the reference state and line calculation, adds valid input bounds, and gates its markers and alert conditions at bar close. It omits decorative fills and labels. The line and bands still update while the candle is open. Compare them with the pinned reference on completed candles before relying on the adaptation.

Adapted from everget under GPL-3.0. Close-confirmed signals are indicator conditions, not trade orders. Syntax acceptance does not establish numerical parity or trading performance.pine
//@version=6
// Copyright (c) 2021-present, Alex Orekhov (everget)
// HalfTrend adaptation: GPL-3.0. https://www.gnu.org/licenses/gpl-3.0.html
// Source: https://github.com/everget/tradingview-pinescript-indicators
// Changes: bounded inputs, simpler display, close-confirmed markers and alerts.
indicator("HalfTrend: confirmed signals", overlay = true)
int amplitude = input.int(2, "Amplitude", minval = 1)
int channelDeviation = input.int(2, "Channel Deviation", minval = 0)
var int trend = 0
var int nextTrend = 0
var float maxLowPrice = nz(low[1], low)
var float minHighPrice = nz(high[1], high)
var float up = 0.0
var float down = 0.0
float arrowUp = na
float arrowDown = na
float atr2 = ta.atr(100) / 2
float dev = channelDeviation * atr2
float highPrice = high[math.abs(ta.highestbars(amplitude))]
float lowPrice = low[math.abs(ta.lowestbars(amplitude))]
float highma = ta.sma(high, amplitude)
float lowma = ta.sma(low, amplitude)
if nextTrend == 1
    maxLowPrice := math.max(lowPrice, maxLowPrice)
    if highma < maxLowPrice and close < nz(low[1], low)
        trend := 1
        nextTrend := 0
        minHighPrice := highPrice
else
    minHighPrice := math.min(highPrice, minHighPrice)
    if lowma > minHighPrice and close > nz(high[1], high)
        trend := 0
        nextTrend := 1
        maxLowPrice := lowPrice
if trend == 0
    if not na(trend[1]) and trend[1] != 0
        up := na(down[1]) ? down : down[1]
        arrowUp := up - atr2
    else
        up := na(up[1]) ? maxLowPrice : math.max(maxLowPrice, up[1])
else
    if not na(trend[1]) and trend[1] != 1
        down := na(up[1]) ? up : up[1]
        arrowDown := down + atr2
    else
        down := na(down[1]) ? minHighPrice : math.min(minHighPrice, down[1])
float ht = trend == 0 ? up : down
float atrHigh = ht + dev
float atrLow = ht - dev
bool buyConfirmed = barstate.isconfirmed and not na(arrowUp) and trend == 0 and trend[1] == 1
bool sellConfirmed = barstate.isconfirmed and not na(arrowDown) and trend == 1 and trend[1] == 0
plot(ht, "HalfTrend", trend == 0 ? color.blue : color.red, 2)
plot(atrHigh, "ATR High", color.red)
plot(atrLow, "ATR Low", color.blue)
plotshape(buyConfirmed ? atrLow : na, "Confirmed buy", shape.triangleup, location.absolute, color.blue, size = size.tiny)
plotshape(sellConfirmed ? atrHigh : na, "Confirmed sell", shape.triangledown, location.absolute, color.red, size = size.tiny)
alertcondition(buyConfirmed, "HalfTrend confirmed buy", "HalfTrend up flip at close: {{exchange}}:{{ticker}}")
alertcondition(sellConfirmed, "HalfTrend confirmed sell", "HalfTrend down flip at close: {{exchange}}:{{ticker}}")

Create the close alert and check its saved configuration

Add the script to the intended chart, open Create Alert, select HalfTrend confirmed buy or HalfTrend confirmed sell, and choose Once Per Bar Close. Create separate alerts if both directions are needed. The original public script also exposes buy/sell alert conditions; choosing a close frequency there waits for the final condition, although its visible provisional arrows can still move intrabar.

  • Alerts run on realtime bars. Old historical arrows do not generate a backlog of notifications.
  • TradingView stores a copy of the script, inputs and chart context when an alert is created. Recreate the alert after changing Amplitude, source code, symbol or timeframe; editing the chart does not update that saved copy.
  • Check the alert log against the saved candle-close record. A notification is not a broker fill, and the ATR band is not automatically a submitted stop order.
  • For a strategy test, define entry timing, exit policy, position size, commissions and slippage separately. Waiting for the close can remove a provisional signal but also delays action until the candle finishes.

Give Pineify an acceptance case, not just an indicator name

The Pine Script AI Coding Agent can draft or edit code from an explicit specification. Supply the public source link, its reuse terms, the initialization rules and the B-to-G fixture. Request a syntax check separately, then compare the generated values on TradingView before creating alerts. No access to a protected script is required or implied.

  • Require the two reversal comparisons, inherited line at a flip and ATR(100) / 2 envelope to remain separate. Ask for intermediate values if the output differs from the fixture.
  • Accept no signal at the equality on C; require the down flip on D and up flip on G. On the alternative D close of 99.0, require no confirmed sell.
  • Check Amplitude = 1, zero channel deviation, an incomplete ATR history and a flat-price sequence. Zero deviation collapses initialized bands to the line; it does not disable the reversal calculation.
Where Pineify fits

Pine Script AI Coding Agent

Draft a HalfTrend adaptation from the public algorithm, initialization and close-confirmation contract. Request syntax checking, then verify its state values and alerts against your TradingView chart.

Draft a confirmed HalfTrend script

Frequently asked questions

Educational algorithm inspection, not investment advice. The numerical candles and trade fills are hypothetical. No live trading performance or complete chart parity test is claimed. Confirmed signals can fail and do not guarantee an execution price or profit.

Sources and verification

Published by Pineify. Pineify is an independent product and is not affiliated with TradingView. Sources support the technical explanations; examples do not establish trading performance.