Skip to content
← Indicator library
tradingviewstructureindicatorpinescript-v6

Photon.AlgoNexta

Multi-timeframe market-structure mapper for confirmed pivots, BOS, CHoCH, strong/weak levels, and equilibrium.

Published by AlgoNexta. AlgoNexta builds and documents evidence-first trading tools so you can inspect the logic before using it.About AlgoNextaIndicator libraryAlgoNexta Research
Published Oct 16, 2026#market-structure#pivot#bos#choch#multi-timeframe#indicator#pinescript-v6#tradingview

Overview

What this indicator does

Photon.AlgoNexta is an overlay indicator that maps market structure across three requested timeframes. It identifies ATR-qualified swing highs and lows, shorter-term internal highs and lows, close-confirmed Breaks of Structure (BOS), and wick-based Changes of Character (CHoCH). The default Photon Profile is `ClassicPhoton`, which uses a `240` higher timeframe (HTF), `15` middle timeframe (MTF), and `1` entry timeframe (LTF). These are data-request timeframes, not a requirement that the chart itself be set to one of them. The `GoldResearch` profile instead uses `60`, `5`, and `1`; `Custom` enables Higher Timeframe, Middle Timeframe, and Entry Timeframe inputs.

Type
indicator
Category
structure
Available in
Pine Script
Source
Open — copy or download

How it works

Read the logic before you use it.

Diagram: When swing structure is mapped
1

When swing structure is mapped

On each requested timeframe, the script waits for a confirmed `ta.pivothigh` or `ta.pivotlow` using **Swing Pivot Strength** `3`. The pivot is retained only when its movement versus the opposing extreme is at least ATR(14) × **Swing ATR Multiplier** `1.0`; therefore, a pivot label is delayed by the right-side pivot bars and may not appear in a quiet range.

Diagram: How BOS and CHoCH are distinguished
2

How BOS and CHoCH are distinguished

A BOS requires the **close** to move beyond the current swing level plus or minus **BOS Buffer Pips** × **Pip Size**; defaults are `0.0` and `0.1`. A CHoCH instead requires an existing opposite internal direction and a wick break of the relevant internal high or low, with both event types evaluated only after bar close.

Diagram: What the chart and alerts show
3

What the chart and alerts show

The overlay prints event labels only for enabled timeframes and categories, while the dashboard summarizes HTF and MTF state. Bullish BOS labels are lime, bearish BOS labels are red, CHoCH labels are purple, swing labels are blue, and optional internal labels are gray; the script caps retained labels at **Maximum Event Labels** `250` by default.

Walkthrough

Watch how it reads the chart.

Live market chart

The logic on real candles.

Backtest evidence

What the numbers actually show.

This script's logic could not be confidently reconstructed into an automated reference backtest, so no performance figures are shown rather than estimated ones.

Verify it in TradingView's Strategy Tester (or the equivalent tool for tradingview) before relying on it.

Vision Grade

What was measured, and how confident we are in it.

Vision Grade requires a reference backtest with enough reconstructed entries to measure — not available for this script yet.

Full breakdown

How the script behaves.

About AlgoNexta

Published by AlgoNexta, an evidence-first platform for building, reviewing, and documenting algorithmic trading tools. This page explains the script's actual logic and intended use; it does not promise profitability or replace verification in TradingView.

What it does

Photon.AlgoNexta is an overlay indicator that maps market structure across three requested timeframes. It identifies ATR-qualified swing highs and lows, shorter-term internal highs and lows, close-confirmed Breaks of Structure (BOS), and wick-based Changes of Character (CHoCH).

The default Photon Profile is ClassicPhoton, which uses a 240 higher timeframe (HTF), 15 middle timeframe (MTF), and 1 entry timeframe (LTF). These are data-request timeframes, not a requirement that the chart itself be set to one of them. The GoldResearch profile instead uses 60, 5, and 1; Custom enables Higher Timeframe, Middle Timeframe, and Entry Timeframe inputs.

How the structure is built

  • A swing pivot uses Swing Pivot Strength (3 by default), so a candidate high or low must have three bars on each side before it is confirmed. This means the pivot is necessarily recognized after the pivot-origin bar.
  • A confirmed swing must also pass an ATR-distance filter: ATR Period is 14, Swing ATR Multiplier is 1.0, and Minimum Swing Bars is 3.
  • Internal highs/lows are mapped from the prior candle when the current closed candle does not extend that prior extreme. The minimum movement qualification is ATR multiplied by Internal ATR Multiplier (0.35), subject to Minimum Internal Bars (1).
  • A bullish BOS occurs only when a closed candle finishes above the active swing high. A bearish BOS occurs only when a closed candle finishes below the active swing low. BOS Buffer Pips defaults to 0.0; its price offset is calculated as that value × Pip Size, which defaults to 0.1.
  • A CHoCH occurs when internal direction is already bearish and price wicks above the mapped internal high, or when internal direction is already bullish and price wicks below the mapped internal low. Unlike BOS, CHoCH uses the bar high/low rather than its close, but is still evaluated only on a confirmed bar.

A chart with no confirmed, ATR-qualified pivot has no active swing level to break, so it cannot produce a BOS. Likewise, CHoCH cannot appear until internal direction has first been established by an internal-level break.

Reading the chart

  • BOS labels: lime for bullish and red for bearish. Labels identify the source timeframe as HTF, MTF, or LTF.
  • CHoCH labels: purple, with up/down arrows for direction.
  • Swing labels: blue SH and SL labels mark qualified swing highs and lows.
  • Internal labels: gray IH and IL labels are optional and disabled by default.
  • Strong/weak levels: HTF strong high is red, HTF strong low is lime, and HTF weak high/low are orange. MTF strong levels use more transparent red/lime lines. These are mapped structure references, not orders or targets.
  • Equilibrium: the aqua HTF line is the midpoint of the currently available strong/weak range.
  • Dashboard: enabled by default, it shows HTF and MTF swing/internal direction, phase, expected flow, strong levels, and range position. “Impulse” means swing and internal directions agree; “Pullback” means they disagree. “Expected Flow” is a state description derived from those directions, not a trading recommendation.

Use the display toggles to control Show HTF Events, Show MTF Events, Show LTF Events, pivots, internal points, BOS, CHoCH, levels, equilibrium, and dashboard. Maximum Event Labels defaults to 250; when exceeded, the script deletes the oldest plotted event labels.

Alerts

The indicator provides four alert conditions: bullish BOS, bearish BOS, bullish CHoCH, and bearish CHoCH. Enable BOS Alerts and Enable CHoCH Alerts both default to enabled. Alerts are based on newly detected events from the timeframes currently enabled for display; disabling a timeframe’s event display also prevents that timeframe from contributing to these aggregate alert conditions.

Timeframes and markets

The default profile is explicitly arranged as 240-minute, 15-minute, and 1-minute structure. The configurable Pip Size tooltip notes that many XAUUSD feeds use 0.1, but the script can be applied to other instruments if the pip-size convention and requested timeframes are adjusted appropriately.

Limitations

  • This is an indicator, not a strategy. It does not call strategy.entry, place orders, calculate position size, or create stop-loss/take-profit logic.
  • Pivots are delayed by the right-side confirmation requirement. They are frozen after confirmation, but they are not known at their original pivot bar in real time.
  • Higher-timeframe values use lookahead_off, and event logic requires confirmed bars. This reduces intrabar and future-data behavior, but multi-timeframe events can only become available once their requested timeframe data is confirmed and delivered to the chart.
  • Require Premium/Discount is context-only in this version; it does not filter events.
  • Strong/weak naming, phase, expected flow, range position, and equilibrium are descriptive outputs of the implemented state logic. They do not independently validate a setup or detect liquidity, points of interest, entries, exits, or performance.
  • This indicator is not financial advice. Historical review, paper trading, and live execution are different evidence levels; use TradingView’s tools and your own testing as the source of truth for results.

Source

Full source code, in every platform.

photon-algonexta.pine · 286 lines · 18.8 KB

Not yet verified on the native platform — test it before relying on it.

The original uploaded source.

Download .pine
//@version=6
indicator("AlgoNexta Photon Trader V1 — Structure", "Photon.AlgoNexta", overlay = true, max_labels_count = 500, max_lines_count = 100, max_boxes_count = 50)

// TradingView indicator port of the causal Phase 1–2 cTrader milestone.
// No POI, liquidity, entry, order, SL/TP, or performance simulation is present.
// Higher-timeframe requests use lookahead_off and events are emitted only after bar close.

string G_GENERAL = "01 General"
string G_TIME = "02 Timeframes"
string G_STRUCTURE = "03 Structure"
string G_DISPLAY = "13 Display"
string G_ALERTS = "14 Alerts"

string profile = input.string("ClassicPhoton", "Photon Profile", options = ["ClassicPhoton", "GoldResearch", "Custom"], group = G_GENERAL)
string customHtf = input.timeframe("240", "Higher Timeframe", group = G_TIME)
string customMtf = input.timeframe("15", "Middle Timeframe", group = G_TIME)
string customLtf = input.timeframe("1", "Entry Timeframe", group = G_TIME)

int swingStrength = input.int(3, "Swing Pivot Strength", minval = 1, maxval = 20, group = G_STRUCTURE)
float bosBufferPips = input.float(0.0, "BOS Buffer Pips", minval = 0.0, step = 0.1, group = G_STRUCTURE)
float pipSize = input.float(0.1, "Pip Size", minval = 0.0000001, step = 0.01, group = G_STRUCTURE, tooltip = "For many XAUUSD feeds this is 0.1. Match this to your broker/feed convention.")
int atrPeriod = input.int(14, "ATR Period", minval = 2, group = G_STRUCTURE)
float swingAtrMultiplier = input.float(1.0, "Swing ATR Multiplier", minval = 0.1, step = 0.05, group = G_STRUCTURE)
float internalAtrMultiplier = input.float(0.35, "Internal ATR Multiplier", minval = 0.05, step = 0.05, group = G_STRUCTURE)
int minimumSwingBars = input.int(3, "Minimum Swing Bars", minval = 1, group = G_STRUCTURE)
int minimumInternalBars = input.int(1, "Minimum Internal Bars", minval = 1, group = G_STRUCTURE)
bool requirePremiumDiscount = input.bool(false, "Require Premium/Discount", group = G_STRUCTURE, tooltip = "Context-only in this structure milestone; it does not filter events.")

bool showHtf = input.bool(true, "Show HTF Events", group = G_DISPLAY)
bool showMtf = input.bool(true, "Show MTF Events", group = G_DISPLAY)
bool showLtf = input.bool(false, "Show LTF Events", group = G_DISPLAY)
bool showSwingPivots = input.bool(true, "Show Swing High/Low", group = G_DISPLAY)
bool showInternal = input.bool(false, "Show Internal High/Low", group = G_DISPLAY)
bool showBos = input.bool(true, "Show BOS", group = G_DISPLAY)
bool showChoch = input.bool(true, "Show CHoCH", group = G_DISPLAY)
bool showStrongWeak = input.bool(true, "Show Strong/Weak Levels", group = G_DISPLAY)
bool showEquilibrium = input.bool(true, "Show Equilibrium", group = G_DISPLAY)
bool showDashboard = input.bool(true, "Show Dashboard", group = G_DISPLAY)
int maximumEventLabels = input.int(250, "Maximum Event Labels", minval = 20, maxval = 480, group = G_DISPLAY)

bool enableBosAlerts = input.bool(true, "Enable BOS Alerts", group = G_ALERTS)
bool enableChochAlerts = input.bool(true, "Enable CHoCH Alerts", group = G_ALERTS)

string htf = profile == "ClassicPhoton" ? "240" : profile == "GoldResearch" ? "60" : customHtf
string mtf = profile == "ClassicPhoton" ? "15" : profile == "GoldResearch" ? "5" : customMtf
string ltf = profile == "ClassicPhoton" ? "1" : profile == "GoldResearch" ? "1" : customLtf

f_dirText(int direction) => direction == 1 ? "Bull" : direction == -1 ? "Bear" : "Unknown"
f_phaseText(int phase) => phase == 1 ? "Impulse" : phase == -1 ? "Pullback" : "Unknown"
f_flowText(int flow) => flow == 1 ? "Bull Continuation" : flow == 2 ? "Bull Pullback" : flow == -1 ? "Bear Continuation" : flow == -2 ? "Bear Pullback" : "Unknown"
f_priceText(float price) => na(price) ? "—" : str.tostring(price, format.mintick)

// MECHANICAL_INTERPRETATION:
// Photon contains discretionary judgment in swing significance and internal mapping.
// This implementation freezes a pivot after right-side confirmation and uses deterministic ATR qualification.
f_structure() =>
    var float swingHigh = na
    var float swingLow = na
    var int swingHighOrigin = na
    var int swingLowOrigin = na
    var bool swingHighBroken = false
    var bool swingLowBroken = false
    var float internalHigh = na
    var float internalLow = na
    var int internalHighOrigin = na
    var int internalLowOrigin = na
    var bool internalHighBroken = false
    var bool internalLowBroken = false
    var int swingDirection = 0
    var int internalDirection = 0
    var float strongHigh = na
    var float strongLow = na
    var float weakHigh = na
    var float weakLow = na
    var int lastBosTime = na
    var int lastBosDirection = 0
    var int lastChochTime = na
    var int lastChochDirection = 0
    var int lastSwingEventTime = na
    var int lastSwingEventType = 0
    var float lastSwingEventPrice = na
    var int lastInternalEventTime = na
    var int lastInternalEventType = 0
    var float lastInternalEventPrice = na

    float atr = ta.atr(atrPeriod)
    float ph = ta.pivothigh(high, swingStrength, swingStrength)
    float pl = ta.pivotlow(low, swingStrength, swingStrength)
    bool confirmed = barstate.isconfirmed

    if confirmed and not na(ph)
        float opposingLow = ta.lowest(low[swingStrength], minimumSwingBars + 1)
        bool qualifiedHigh = ph - opposingLow >= atr[swingStrength] * swingAtrMultiplier
        if qualifiedHigh
            swingHigh := ph
            swingHighOrigin := bar_index - swingStrength
            swingHighBroken := false
            lastSwingEventTime := time
            lastSwingEventType := 1
            lastSwingEventPrice := ph
            if swingDirection == -1
                strongHigh := ph
            else
                weakHigh := ph

    if confirmed and not na(pl)
        float opposingHigh = ta.highest(high[swingStrength], minimumSwingBars + 1)
        bool qualifiedLow = opposingHigh - pl >= atr[swingStrength] * swingAtrMultiplier
        if qualifiedLow
            swingLow := pl
            swingLowOrigin := bar_index - swingStrength
            swingLowBroken := false
            lastSwingEventTime := time
            lastSwingEventType := -1
            lastSwingEventPrice := pl
            if swingDirection == 1
                strongLow := pl
            else
                weakLow := pl

    // Prior candle becomes a candidate when this closed candle fails to extend its extreme.
    float minInternalMove = atr * internalAtrMultiplier
    bool highCandidate = confirmed and high <= high[1] and (na(internalLow) or high[1] - internalLow >= minInternalMove)
    bool lowCandidate = confirmed and low >= low[1] and (na(internalHigh) or internalHigh - low[1] >= minInternalMove)
    if highCandidate and (na(internalLowOrigin) or bar_index - internalLowOrigin >= minimumInternalBars)
        internalHigh := high[1]
        internalHighOrigin := bar_index - 1
        internalHighBroken := false
        lastInternalEventTime := time
        lastInternalEventType := 1
        lastInternalEventPrice := internalHigh
    if lowCandidate and (na(internalHighOrigin) or bar_index - internalHighOrigin >= minimumInternalBars)
        internalLow := low[1]
        internalLowOrigin := bar_index - 1
        internalLowBroken := false
        lastInternalEventTime := time
        lastInternalEventType := -1
        lastInternalEventPrice := internalLow

    // PHOTON_ORIGINAL: Swing BOS requires a candle close beyond the mapped wick level.
    bool bullBos = confirmed and not swingHighBroken and not na(swingHigh) and close > swingHigh + bosBufferPips * pipSize
    bool bearBos = confirmed and not swingLowBroken and not na(swingLow) and close < swingLow - bosBufferPips * pipSize
    if bullBos
        swingHighBroken := true
        swingDirection := 1
        strongLow := swingLow
        weakHigh := swingHigh
        lastBosTime := time
        lastBosDirection := 1
    if bearBos
        swingLowBroken := true
        swingDirection := -1
        strongHigh := swingHigh
        weakLow := swingLow
        lastBosTime := time
        lastBosDirection := -1

    // PHOTON_ORIGINAL: CHoCH is the first aggressive wick break against mapped Internal behaviour.
    bool bullChoch = confirmed and internalDirection == -1 and not internalHighBroken and not na(internalHigh) and high > internalHigh
    bool bearChoch = confirmed and internalDirection == 1 and not internalLowBroken and not na(internalLow) and low < internalLow
    if bullChoch
        internalHighBroken := true
        internalDirection := 1
        lastChochTime := time
        lastChochDirection := 1
    if bearChoch
        internalLowBroken := true
        internalDirection := -1
        lastChochTime := time
        lastChochDirection := -1

    // Bootstrap internal direction from a mapped break; this is not emitted as CHoCH.
    if confirmed and internalDirection == 0
        if not na(internalHigh) and high > internalHigh
            internalDirection := 1
            internalHighBroken := true
        else if not na(internalLow) and low < internalLow
            internalDirection := -1
            internalLowBroken := true

    bool counter = swingDirection != 0 and internalDirection != 0 and swingDirection != internalDirection
    int phase = swingDirection == 0 ? 0 : counter ? -1 : 1
    int expectedFlow = swingDirection == 1 ? (counter ? 2 : 1) : swingDirection == -1 ? (counter ? -2 : -1) : 0
    float rangeHigh = not na(strongHigh) ? strongHigh : weakHigh
    float rangeLow = not na(strongLow) ? strongLow : weakLow
    float relativePosition = not na(rangeHigh) and not na(rangeLow) and rangeHigh > rangeLow ? (close - rangeLow) / (rangeHigh - rangeLow) : na
    float equilibrium = not na(rangeHigh) and not na(rangeLow) ? (rangeHigh + rangeLow) * 0.5 : na

    [swingDirection, internalDirection, phase, expectedFlow, strongHigh, strongLow, weakHigh, weakLow, equilibrium, relativePosition,
     lastBosTime, lastBosDirection, lastChochTime, lastChochDirection, lastSwingEventTime, lastSwingEventType, lastSwingEventPrice,
     lastInternalEventTime, lastInternalEventType, lastInternalEventPrice]

[hSwing, hInternal, hPhase, hFlow, hStrongHigh, hStrongLow, hWeakHigh, hWeakLow, hEq, hPosition, hBosTime, hBosDir, hChochTime, hChochDir, hSwingTime, hSwingType, hSwingPrice, hInternalTime, hInternalType, hInternalPrice] = request.security(syminfo.tickerid, htf, f_structure(), gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_off)
[mSwing, mInternal, mPhase, mFlow, mStrongHigh, mStrongLow, mWeakHigh, mWeakLow, mEq, mPosition, mBosTime, mBosDir, mChochTime, mChochDir, mSwingTime, mSwingType, mSwingPrice, mInternalTime, mInternalType, mInternalPrice] = request.security(syminfo.tickerid, mtf, f_structure(), gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_off)
[lSwing, lInternal, lPhase, lFlow, lStrongHigh, lStrongLow, lWeakHigh, lWeakLow, lEq, lPosition, lBosTime, lBosDir, lChochTime, lChochDir, lSwingTime, lSwingType, lSwingPrice, lInternalTime, lInternalType, lInternalPrice] = request.security(syminfo.tickerid, ltf, f_structure(), gaps = barmerge.gaps_off, lookahead = barmerge.lookahead_off)

bool hNewBos = not na(hBosTime) and (na(hBosTime[1]) or hBosTime != hBosTime[1])
bool mNewBos = not na(mBosTime) and (na(mBosTime[1]) or mBosTime != mBosTime[1])
bool lNewBos = not na(lBosTime) and (na(lBosTime[1]) or lBosTime != lBosTime[1])
bool hNewChoch = not na(hChochTime) and (na(hChochTime[1]) or hChochTime != hChochTime[1])
bool mNewChoch = not na(mChochTime) and (na(mChochTime[1]) or mChochTime != mChochTime[1])
bool lNewChoch = not na(lChochTime) and (na(lChochTime[1]) or lChochTime != lChochTime[1])
bool hNewSwing = not na(hSwingTime) and (na(hSwingTime[1]) or hSwingTime != hSwingTime[1])
bool mNewSwing = not na(mSwingTime) and (na(mSwingTime[1]) or mSwingTime != mSwingTime[1])
bool lNewSwing = not na(lSwingTime) and (na(lSwingTime[1]) or lSwingTime != lSwingTime[1])
bool hNewInternal = not na(hInternalTime) and (na(hInternalTime[1]) or hInternalTime != hInternalTime[1])
bool mNewInternal = not na(mInternalTime) and (na(mInternalTime[1]) or mInternalTime != mInternalTime[1])
bool lNewInternal = not na(lInternalTime) and (na(lInternalTime[1]) or lInternalTime != lInternalTime[1])

var label[] eventLabels = array.new_label()
f_event(bool event, string role, string eventName, int direction, float eventPrice, color eventColor) =>
    if event
        float y = na(eventPrice) ? close : eventPrice
        label item = label.new(bar_index, y, role + " " + eventName + (direction == 1 ? " ↑" : " ↓"), style = direction == 1 ? label.style_label_up : label.style_label_down, color = eventColor, textcolor = color.white, size = size.tiny)
        array.push(eventLabels, item)
        while array.size(eventLabels) > maximumEventLabels
            label.delete(array.shift(eventLabels))

if showBos
    f_event(showHtf and hNewBos, "HTF", "BOS", hBosDir, hBosDir == 1 ? hWeakHigh : hWeakLow, color.new(hBosDir == 1 ? color.lime : color.red, 0))
    f_event(showMtf and mNewBos, "MTF", "BOS", mBosDir, mBosDir == 1 ? mWeakHigh : mWeakLow, color.new(mBosDir == 1 ? color.lime : color.red, 15))
    f_event(showLtf and lNewBos, "LTF", "BOS", lBosDir, lBosDir == 1 ? lWeakHigh : lWeakLow, color.new(lBosDir == 1 ? color.lime : color.red, 30))
if showChoch
    f_event(showHtf and hNewChoch, "HTF", "CHoCH", hChochDir, close, color.purple)
    f_event(showMtf and mNewChoch, "MTF", "CHoCH", mChochDir, close, color.new(color.purple, 15))
    f_event(showLtf and lNewChoch, "LTF", "CHoCH", lChochDir, close, color.new(color.purple, 30))
if showSwingPivots
    f_event(showHtf and hNewSwing, "HTF", hSwingType == 1 ? "SH" : "SL", hSwingType == 1 ? -1 : 1, hSwingPrice, color.new(color.blue, 20))
    f_event(showMtf and mNewSwing, "MTF", mSwingType == 1 ? "SH" : "SL", mSwingType == 1 ? -1 : 1, mSwingPrice, color.new(color.blue, 40))
    f_event(showLtf and lNewSwing, "LTF", lSwingType == 1 ? "SH" : "SL", lSwingType == 1 ? -1 : 1, lSwingPrice, color.new(color.blue, 60))
if showInternal
    f_event(showHtf and hNewInternal, "HTF", hInternalType == 1 ? "IH" : "IL", hInternalType == 1 ? -1 : 1, hInternalPrice, color.new(color.gray, 20))
    f_event(showMtf and mNewInternal, "MTF", mInternalType == 1 ? "IH" : "IL", mInternalType == 1 ? -1 : 1, mInternalPrice, color.new(color.gray, 40))
    f_event(showLtf and lNewInternal, "LTF", lInternalType == 1 ? "IH" : "IL", lInternalType == 1 ? -1 : 1, lInternalPrice, color.new(color.gray, 60))

plot(showStrongWeak ? hStrongHigh : na, "HTF Strong High", color = color.new(color.red, 5), linewidth = 2, style = plot.style_linebr)
plot(showStrongWeak ? hStrongLow : na, "HTF Strong Low", color = color.new(color.lime, 5), linewidth = 2, style = plot.style_linebr)
plot(showStrongWeak ? hWeakHigh : na, "HTF Weak High", color = color.new(color.orange, 20), linewidth = 1, style = plot.style_linebr)
plot(showStrongWeak ? hWeakLow : na, "HTF Weak Low", color = color.new(color.orange, 20), linewidth = 1, style = plot.style_linebr)
plot(showStrongWeak ? mStrongHigh : na, "MTF Strong High", color = color.new(color.red, 55), linewidth = 1, style = plot.style_linebr)
plot(showStrongWeak ? mStrongLow : na, "MTF Strong Low", color = color.new(color.lime, 55), linewidth = 1, style = plot.style_linebr)
plot(showEquilibrium ? hEq : na, "HTF Equilibrium", color = color.new(color.aqua, 35), linewidth = 1, style = plot.style_linebr)

bool anyBullBos = (showHtf and hNewBos and hBosDir == 1) or (showMtf and mNewBos and mBosDir == 1) or (showLtf and lNewBos and lBosDir == 1)
bool anyBearBos = (showHtf and hNewBos and hBosDir == -1) or (showMtf and mNewBos and mBosDir == -1) or (showLtf and lNewBos and lBosDir == -1)
bool anyBullChoch = (showHtf and hNewChoch and hChochDir == 1) or (showMtf and mNewChoch and mChochDir == 1) or (showLtf and lNewChoch and lChochDir == 1)
bool anyBearChoch = (showHtf and hNewChoch and hChochDir == -1) or (showMtf and mNewChoch and mChochDir == -1) or (showLtf and lNewChoch and lChochDir == -1)
alertcondition(enableBosAlerts and anyBullBos, "Photon Bullish BOS", "Photon bullish close-confirmed BOS on {{ticker}} at {{close}}")
alertcondition(enableBosAlerts and anyBearBos, "Photon Bearish BOS", "Photon bearish close-confirmed BOS on {{ticker}} at {{close}}")
alertcondition(enableChochAlerts and anyBullChoch, "Photon Bullish CHoCH", "Photon bullish wick-based CHoCH on {{ticker}} at {{close}}")
alertcondition(enableChochAlerts and anyBearChoch, "Photon Bearish CHoCH", "Photon bearish wick-based CHoCH on {{ticker}} at {{close}}")

var table dashboard = table.new(position.top_right, 3, 10, bgcolor = color.new(color.black, 12), border_width = 1)
if barstate.islast and showDashboard
    table.cell(dashboard, 0, 0, "ALGONEXTA PHOTON V1", text_color = color.white, bgcolor = color.new(color.blue, 40))
    table.merge_cells(dashboard, 0, 0, 2, 0)
    table.cell(dashboard, 0, 1, "Role", text_color = color.silver)
    table.cell(dashboard, 1, 1, "HTF " + htf, text_color = color.aqua)
    table.cell(dashboard, 2, 1, "MTF " + mtf, text_color = color.aqua)
    table.cell(dashboard, 0, 2, "Swing", text_color = color.silver)
    table.cell(dashboard, 1, 2, f_dirText(hSwing), text_color = hSwing == 1 ? color.lime : hSwing == -1 ? color.red : color.orange)
    table.cell(dashboard, 2, 2, f_dirText(mSwing), text_color = mSwing == 1 ? color.lime : mSwing == -1 ? color.red : color.orange)
    table.cell(dashboard, 0, 3, "Internal", text_color = color.silver)
    table.cell(dashboard, 1, 3, f_dirText(hInternal), text_color = hInternal == 1 ? color.lime : hInternal == -1 ? color.red : color.orange)
    table.cell(dashboard, 2, 3, f_dirText(mInternal), text_color = mInternal == 1 ? color.lime : mInternal == -1 ? color.red : color.orange)
    table.cell(dashboard, 0, 4, "Phase", text_color = color.silver)
    table.cell(dashboard, 1, 4, f_phaseText(hPhase), text_color = color.white)
    table.cell(dashboard, 2, 4, f_phaseText(mPhase), text_color = color.white)
    table.cell(dashboard, 0, 5, "Expected Flow", text_color = color.silver)
    table.cell(dashboard, 1, 5, f_flowText(hFlow), text_color = color.white)
    table.cell(dashboard, 2, 5, f_flowText(mFlow), text_color = color.white)
    table.cell(dashboard, 0, 6, "Strong H", text_color = color.silver)
    table.cell(dashboard, 1, 6, f_priceText(hStrongHigh), text_color = color.white)
    table.cell(dashboard, 2, 6, f_priceText(mStrongHigh), text_color = color.white)
    table.cell(dashboard, 0, 7, "Strong L", text_color = color.silver)
    table.cell(dashboard, 1, 7, f_priceText(hStrongLow), text_color = color.white)
    table.cell(dashboard, 2, 7, f_priceText(mStrongLow), text_color = color.white)
    table.cell(dashboard, 0, 8, "Range Pos.", text_color = color.silver)
    table.cell(dashboard, 1, 8, na(hPosition) ? "—" : str.tostring(hPosition, "#.0%"), text_color = color.white)
    table.cell(dashboard, 2, 8, na(mPosition) ? "—" : str.tostring(mPosition, "#.0%"), text_color = color.white)
    table.cell(dashboard, 0, 9, "Status", text_color = color.silver)
    table.cell(dashboard, 1, 9, "STRUCTURE ONLY", text_color = color.yellow)
    table.merge_cells(dashboard, 1, 9, 2, 9)
else if barstate.islast
    table.clear(dashboard, 0, 0, 2, 9)

FAQ

Common questions.

What does Photon.AlgoNexta detect?▾

It maps ATR-qualified swing pivots and internal pivots across HTF, MTF, and LTF requests, then marks close-confirmed BOS and wick-based CHoCH events. It also derives strong/weak reference levels, equilibrium, direction, phase, and expected-flow states.

Does Photon.AlgoNexta repaint?▾

Swing pivots require right-side confirmation, so they are identified after the pivot-origin bar rather than at that bar in real time. The script uses confirmed bars and `lookahead_off` for higher-timeframe requests; however, multi-timeframe events remain dependent on completion of their requested timeframe.

Does this indicator place trades or provide stop-loss and take-profit orders?▾

No. It is an overlay indicator only and contains no strategy entries, exits, position sizing, SL/TP, or performance simulation.

Which timeframes does it use by default?▾

With Photon Profile set to `ClassicPhoton`, the script requests 240-minute HTF, 15-minute MTF, and 1-minute LTF data. `GoldResearch` uses 60, 5, and 1 minutes, while `Custom` uses the three timeframe inputs.

How do BOS and CHoCH alerts work?▾

BOS alerts require a newly detected bullish or bearish BOS from a displayed timeframe, while CHoCH alerts require a newly detected directional CHoCH. Both alert toggles default to enabled, and alert conditions are evaluated on confirmed bars.

Is Photon.AlgoNexta financial advice or proof of live performance?▾

No. It is not financial advice and the script makes no live-performance claim. TradingView Strategy Tester is not applicable to this indicator because it does not place strategy orders; use your own historical review, paper trading, and live results as the source of truth.

Want a version tuned to your market?

Describe the change in plain English and AlgoNexta rebuilds it as a fresh Pine v6 script — with its own explanation, evidence, and walkthrough.

Build your own version

Educational content only — not financial advice. TradingView is the source of truth for live data, compilation, and Strategy Tester results.

We use cookies to understand how the site is used and improve it. We only load analytics after you accept. Privacy Policy