Indicator · Pine Script v5 · On the chart

Session Statistical Levels

by TamaraKGreen· code credited to lucymatos

This indicator overlays statistical price range levels across key trading sessions, including Asia, London, NY Morning, and NY Afternoon, as well as an optional custom session.

View on GitHub

GitHub stars46on the repository
Pine versionv5runs as is
Lines of code1,623
Settings38inputs
LicenceNone statedfile: MPL-2.0
Last update7 weeks ago4 Sep 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

1,623 lines of Pine Script v5 from Session Statistical Levels.txt, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

Session Statistical Levels.txt
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © lucymatos

//@version=5
indicator(
     title="Session Statistical Levels",
     shorttitle       = "Sess Stats",
     overlay          = true,
     max_lines_count  = 500,
     max_labels_count = 500,
     max_boxes_count  = 500,
     max_bars_back    = 5000)

// ═══════════════════════════════════════════════════════════════════
// SECTION 1 — INPUTS
// ═══════════════════════════════════════════════════════════════════

var g_GLOBAL = "Global Settings"
i_label_size  = input.string("Tiny", "Label Size",
                 options=["Tiny","Small","Normal"], group=g_GLOBAL)

// ─── Sessions ─────────────────────────────────────────────────────
var g_SESS = "Sessions"
i_show_asia   = input.bool(true,  "Asia        (19:00–02:00 ET)", group=g_SESS)
i_col_asia    = input.color(color.rgb(255, 153, 0),   "Asia colour",         group=g_SESS)
i_show_lon    = input.bool(true,  "London      (02:00–08:00 ET)", group=g_SESS)
i_col_lon     = input.color(color.rgb(41,  98,  255), "London colour",       group=g_SESS)
i_show_nyam   = input.bool(true,  "NY Morning  (08:00–12:00 ET)", group=g_SESS)
i_col_nyam    = input.color(color.rgb(0,   150, 136), "NY Morning colour",   group=g_SESS)
i_show_nypm   = input.bool(true,  "NY Afternoon (12:00–17:00 ET)", group=g_SESS)
i_col_nypm    = input.color(color.rgb(156, 39,  176), "NY Afternoon colour", group=g_SESS)
i_show_cust   = input.bool(false, "Custom Session",               group=g_SESS)
i_cust_start  = input.string("0900", "  Start (HHMM ET)",         group=g_SESS)
i_cust_end    = input.string("1200", "  End   (HHMM ET)",         group=g_SESS)
i_cust_label  = input.string("Custom", "  Label",                 group=g_SESS)
i_col_cust    = input.color(color.rgb(100, 100, 100), "Custom colour",       group=g_SESS)

// ─── Range Bands ──────────────────────────────────────────────────
var g_RNG = "Range Bands  (symmetric H-L percentiles)"
i_rng_p50     = input.bool(true,  "Median (P50)",          group=g_RNG)
i_rng_iqr     = input.bool(true,  "IQR (P25 / P75)",       group=g_RNG)
i_rng_p10p90  = input.bool(true,  "P10 / P90",             group=g_RNG)
i_rng_mean    = input.bool(true,  "Mean",                   group=g_RNG)
i_rng_fills   = input.bool(true,  "Show Fills",             group=g_RNG)
i_rng_style   = input.string("Dotted", "Line Style",
                 options=["Solid","Dashed","Dotted"],        group=g_RNG)
i_rng_width   = input.int(1, "Line Width", minval=1, maxval=4, group=g_RNG)
i_col_p50     = input.color(color.rgb(20,  20,  20),  "P50 colour",    group=g_RNG)
i_col_iqr     = input.color(color.rgb(80,  80,  80),  "IQR colour",    group=g_RNG)
i_col_p10p90  = input.color(color.rgb(130, 130, 130), "P10/P90 colour",group=g_RNG)
i_col_mean    = input.color(color.rgb(60,  60,  160), "Mean colour",   group=g_RNG)

// ─── MFE / MAE Bands ──────────────────────────────────────────────
var g_EXC = "MFE / MAE Bands  (directional excursion)"
i_show_exc    = input.bool(true,  "Show MFE / MAE Bands",  group=g_EXC)
i_bull_bear   = input.bool(false, "Split Bull / Bear sessions",
                 tooltip="Show separate levels for sessions that closed above/below open",
                 group=g_EXC)
i_exc_style   = input.string("Solid", "Line Style",
                 options=["Solid","Dashed","Dotted"],        group=g_EXC)
i_exc_width   = input.int(1, "Line Width", minval=1, maxval=4, group=g_EXC)
i_col_mfe     = input.color(color.rgb(30,  140, 30),  "MFE colour",    group=g_EXC)
i_col_mae     = input.color(color.rgb(180, 30,  30),  "MAE colour",    group=g_EXC)

// ─── Overview Table ───────────────────────────────────────────────
var g_TBL1 = "Overview Table"
i_tbl1_show   = input.bool(true, "Show Overview Table",     group=g_TBL1)
i_tbl1_pos    = input.string("Bottom Left", "Position",
                 options=["Top Left","Top Right","Top Center",
                          "Middle Left","Middle Center","Middle Right",
                          "Bottom Left","Bottom Center","Bottom Right"],
                 group=g_TBL1)
i_tbl1_size   = input.string("Tiny", "Text Size",
                 options=["Tiny","Small","Normal"],          group=g_TBL1)

// ─── Live Level Table ─────────────────────────────────────────────
var g_TBL2 = "Live Level Table"
i_tbl2_show   = input.bool(true, "Show Live Level Table",   group=g_TBL2)
i_tbl2_pos    = input.string("Bottom Right", "Position",
                 options=["Top Left","Top Right","Top Center",
                          "Middle Left","Middle Center","Middle Right",
                          "Bottom Left","Bottom Center","Bottom Right"],
                 group=g_TBL2)
i_tbl2_size   = input.string("Tiny", "Text Size",
                 options=["Tiny","Small","Normal"],          group=g_TBL2)

// ─── Label offset ─────────────────────────────────────────────────
i_proj_bars   = input.int(10, "Label Offset (bars)",
                 minval=1, maxval=50, group=g_GLOBAL)

// ═══════════════════════════════════════════════════════════════════
// SECTION 2 — HELPERS
// ═══════════════════════════════════════════════════════════════════

TZ = "America/New_York"

f_lbl_size() =>
    i_label_size == "Tiny" ? size.tiny :
     i_label_size == "Small" ? size.small : size.normal

f_tbl_size(s) =>
    s == "Tiny" ? size.tiny : s == "Small" ? size.small : size.normal

f_tpos(s) =>
    switch s
        "Top Left"      => position.top_left
        "Top Right"     => position.top_right
        "Top Center"    => position.top_center
        "Middle Left"   => position.middle_left
        "Middle Center" => position.middle_center
        "Middle Right"  => position.middle_right
        "Bottom Left"   => position.bottom_left
        "Bottom Center" => position.bottom_center
        => position.bottom_right

f_line_style(s) =>
    switch s
        "Solid"  => line.style_solid
        "Dashed" => line.style_dashed
        => line.style_dotted

f_pct_val(arr, p) =>
    array.size(arr) >= 2 ? array.percentile_nearest_rank(arr, p) : float(na)

f_pct_rank(arr, val) =>
    n = array.size(arr)
    if n == 0
        int(na)
    else
        count = 0
        for i = 0 to n - 1
            if array.get(arr, i) <= val
                count += 1
        math.round((count / n) * 100)

f_fmt_pts(v) =>
    not na(v) ?
     (v >= 0 ? "+" : "") + str.format("{0,number,#.#}", v) + " pts" : "—"

f_fmt_p(v) =>
    not na(v) ? str.format("{0,number,#.#}", v) : "—"

f_rev_str(tot, rev) =>
    tot > 0 ? str.tostring(math.round((rev / tot) * 100)) + "%" : "—"

// ═══════════════════════════════════════════════════════════════════
// SECTION 3 — SESSION DETECTION
// ═══════════════════════════════════════════════════════════════════

asia_tf  = "1900-0200"
lon_tf   = "0200-0800"
nyam_tf  = "0800-1200"
nypm_tf  = "1200-1700"
cust_tf  = i_cust_start + "-" + i_cust_end

in_asia  = not na(time(timeframe.period, asia_tf,  TZ))
in_lon   = not na(time(timeframe.period, lon_tf,   TZ))
in_nyam  = not na(time(timeframe.period, nyam_tf,  TZ))
in_nypm  = not na(time(timeframe.period, nypm_tf,  TZ))
in_cust  = not na(time(timeframe.period, cust_tf,  TZ))

asia_start  = in_asia  and not in_asia[1]
lon_start   = in_lon   and not in_lon[1]
nyam_start  = in_nyam  and not in_nyam[1]
nypm_start  = in_nypm  and not in_nypm[1]
cust_start  = in_cust  and not in_cust[1]

asia_end    = not in_asia  and in_asia[1]
lon_end     = not in_lon   and in_lon[1]
nyam_end    = not in_nyam  and in_nyam[1]
nypm_end    = not in_nypm  and in_nypm[1]
cust_end    = not in_cust  and in_cust[1]

// ═══════════════════════════════════════════════════════════════════
// SECTION 4 — SESSION OHLC TRACKING
// Running high/low/close updated every bar within session.
// Open captured at first bar. All used for stat recording at end.
// ═══════════════════════════════════════════════════════════════════

var float asia_o  = na, var float asia_h  = na
var float asia_l  = na, var float asia_c  = na

var float lon_o   = na, var float lon_h   = na
var float lon_l   = na, var float lon_c   = na

var float nyam_o  = na, var float nyam_h  = na
var float nyam_l  = na, var float nyam_c  = na

var float nypm_o  = na, var float nypm_h  = na
var float nypm_l  = na, var float nypm_c  = na

var float cust_o  = na, var float cust_h  = na
var float cust_l  = na, var float cust_c  = na

// Asia
if asia_start
    asia_o := open,  asia_h := high
    asia_l := low,   asia_c := close
else if in_asia
    asia_h := math.max(asia_h, high)
    asia_l := math.min(asia_l, low)
    asia_c := close

// London
if lon_start
    lon_o := open,  lon_h := high
    lon_l := low,   lon_c := close
else if in_lon
    lon_h := math.max(lon_h, high)
    lon_l := math.min(lon_l, low)
    lon_c := close

// NY Morning
if nyam_start
    nyam_o := open,  nyam_h := high
    nyam_l := low,   nyam_c := close
else if in_nyam
    nyam_h := math.max(nyam_h, high)
    nyam_l := math.min(nyam_l, low)
    nyam_c := close

// NY Afternoon
if nypm_start
    nypm_o := open,  nypm_h := high
    nypm_l := low,   nypm_c := close
else if in_nypm
    nypm_h := math.max(nypm_h, high)
    nypm_l := math.min(nypm_l, low)
    nypm_c := close

// Custom
if cust_start
    cust_o := open,  cust_h := high
    cust_l := low,   cust_c := close
else if in_cust
    cust_h := math.max(cust_h, high)
    cust_l := math.min(cust_l, low)
    cust_c := close

// ═══════════════════════════════════════════════════════════════════
// SECTION 5 — STAT ARRAYS
// Per session, stored as points from session open:
//   _rng        : full range H-L  (for symmetric range bands)
//   _mfe        : max upside from open  (all sessions)
//   _mae        : max downside from open (all sessions)
//   _bull_mfe   : MFE on bull sessions only (close > open)
//   _bull_mae   : MAE on bull sessions only
//   _bear_mfe   : MFE on bear sessions only (close < open)
//   _bear_mae   : MAE on bear sessions only
//   _cls        : close deviation from open (signed, for reversion)
//   _bull / _bear : session direction counters
// ═══════════════════════════════════════════════════════════════════

// ─── Asia ─────────────────────────────────────────────────────────
var float[] asia_rng      = array.new_float(0)
var float[] asia_mfe      = array.new_float(0)
var float[] asia_mae      = array.new_float(0)
var float[] asia_bull_mfe = array.new_float(0)
var float[] asia_bull_mae = array.new_float(0)
var float[] asia_bear_mfe = array.new_float(0)
var float[] asia_bear_mae = array.new_float(0)
var float[] asia_cls      = array.new_float(0)
var int     asia_bull_ct  = 0
var int     asia_bear_ct  = 0

// ─── London ───────────────────────────────────────────────────────
var float[] lon_rng       = array.new_float(0)
var float[] lon_mfe       = array.new_float(0)
var float[] lon_mae       = array.new_float(0)
var float[] lon_bull_mfe  = array.new_float(0)
var float[] lon_bull_mae  = array.new_float(0)
var float[] lon_bear_mfe  = array.new_float(0)
var float[] lon_bear_mae  = array.new_float(0)
var float[] lon_cls       = array.new_float(0)
var int     lon_bull_ct   = 0
var int     lon_bear_ct   = 0

// ─── NY Morning ───────────────────────────────────────────────────
var float[] nyam_rng      = array.new_float(0)
var float[] nyam_mfe      = array.new_float(0)
var float[] nyam_mae      = array.new_float(0)
var float[] nyam_bull_mfe = array.new_float(0)
var float[] nyam_bull_mae = array.new_float(0)
var float[] nyam_bear_mfe = array.new_float(0)
var float[] nyam_bear_mae = array.new_float(0)
var float[] nyam_cls      = array.new_float(0)
var int     nyam_bull_ct  = 0
var int     nyam_bear_ct  = 0

// ─── NY Afternoon ─────────────────────────────────────────────────
var float[] nypm_rng      = array.new_float(0)
var float[] nypm_mfe      = array.new_float(0)
var float[] nypm_mae      = array.new_float(0)
var float[] nypm_bull_mfe = array.new_float(0)
var float[] nypm_bull_mae = array.new_float(0)
var float[] nypm_bear_mfe = array.new_float(0)
var float[] nypm_bear_mae = array.new_float(0)
var float[] nypm_cls      = array.new_float(0)
var int     nypm_bull_ct  = 0
var int     nypm_bear_ct  = 0

// ─── Custom ───────────────────────────────────────────────────────
var float[] cust_rng      = array.new_float(0)
var float[] cust_mfe      = array.new_float(0)
var float[] cust_mae      = array.new_float(0)
var float[] cust_bull_mfe = array.new_float(0)
var float[] cust_bull_mae = array.new_float(0)
var float[] cust_bear_mfe = array.new_float(0)
var float[] cust_bear_mae = array.new_float(0)
var float[] cust_cls      = array.new_float(0)
var int     cust_bull_ct  = 0
var int     cust_bear_ct  = 0

// ═══════════════════════════════════════════════════════════════════
// SECTION 6 — REVERSION COUNTERS + SESSION RECORDING
//
// Reversion counters — per session, per level (P25/P50/P75/P90)
// for both MFE (upside) and MAE (downside):
//   _tot : sessions that reached this level
//   _rev : of those, closed back within cls IQR (near open)
//   _nxt : of those, continued to the next level
//
// f_record_session() called at session end — pushes to arrays,
// updates bull/bear counts and all reversion counters atomically.
// ═══════════════════════════════════════════════════════════════════

// ─── Asia reversion counters ──────────────────────────────────────
var int asia_mfe25_tot = 0, var int asia_mfe25_nxt = 0, var int asia_mfe25_opp = 0
var int asia_mfe50_tot = 0, var int asia_mfe50_nxt = 0, var int asia_mfe50_opp = 0
var int asia_mfe75_tot = 0, var int asia_mfe75_nxt = 0, var int asia_mfe75_opp = 0
var int asia_mfe90_tot = 0, var int asia_mfe90_opp = 0
var int asia_mae25_tot = 0, var int asia_mae25_nxt = 0, var int asia_mae25_opp = 0
var int asia_mae50_tot = 0, var int asia_mae50_nxt = 0, var int asia_mae50_opp = 0
var int asia_mae75_tot = 0, var int asia_mae75_nxt = 0, var int asia_mae75_opp = 0
var int asia_mae90_tot = 0, var int asia_mae90_opp = 0
var int asia_sess_tot  = 0

// ─── London reversion counters ────────────────────────────────────
var int lon_mfe25_tot  = 0, var int lon_mfe25_nxt  = 0, var int lon_mfe25_opp  = 0
var int lon_mfe50_tot  = 0, var int lon_mfe50_nxt  = 0, var int lon_mfe50_opp  = 0
var int lon_mfe75_tot  = 0, var int lon_mfe75_nxt  = 0, var int lon_mfe75_opp  = 0
var int lon_mfe90_tot  = 0, var int lon_mfe90_opp  = 0
var int lon_mae25_tot  = 0, var int lon_mae25_nxt  = 0, var int lon_mae25_opp  = 0
var int lon_mae50_tot  = 0, var int lon_mae50_nxt  = 0, var int lon_mae50_opp  = 0
var int lon_mae75_tot  = 0, var int lon_mae75_nxt  = 0, var int lon_mae75_opp  = 0
var int lon_mae90_tot  = 0, var int lon_mae90_opp  = 0
var int lon_sess_tot   = 0

// ─── NY Morning reversion counters ────────────────────────────────
var int nyam_mfe25_tot = 0, var int nyam_mfe25_nxt = 0, var int nyam_mfe25_opp = 0
var int nyam_mfe50_tot = 0, var int nyam_mfe50_nxt = 0, var int nyam_mfe50_opp = 0
var int nyam_mfe75_tot = 0, var int nyam_mfe75_nxt = 0, var int nyam_mfe75_opp = 0
var int nyam_mfe90_tot = 0, var int nyam_mfe90_opp = 0
var int nyam_mae25_tot = 0, var int nyam_mae25_nxt = 0, var int nyam_mae25_opp = 0
var int nyam_mae50_tot = 0, var int nyam_mae50_nxt = 0, var int nyam_mae50_opp = 0
var int nyam_mae75_tot = 0, var int nyam_mae75_nxt = 0, var int nyam_mae75_opp = 0
var int nyam_mae90_tot = 0, var int nyam_mae90_opp = 0
var int nyam_sess_tot  = 0

// ─── NY Afternoon reversion counters ──────────────────────────────
var int nypm_mfe25_tot = 0, var int nypm_mfe25_nxt = 0, var int nypm_mfe25_opp = 0
var int nypm_mfe50_tot = 0, var int nypm_mfe50_nxt = 0, var int nypm_mfe50_opp = 0
var int nypm_mfe75_tot = 0, var int nypm_mfe75_nxt = 0, var int nypm_mfe75_opp = 0
var int nypm_mfe90_tot = 0, var int nypm_mfe90_opp = 0
var int nypm_mae25_tot = 0, var int nypm_mae25_nxt = 0, var int nypm_mae25_opp = 0
var int nypm_mae50_tot = 0, var int nypm_mae50_nxt = 0, var int nypm_mae50_opp = 0
var int nypm_mae75_tot = 0, var int nypm_mae75_nxt = 0, var int nypm_mae75_opp = 0
var int nypm_mae90_tot = 0, var int nypm_mae90_opp = 0
var int nypm_sess_tot  = 0

// ─── Custom reversion counters ────────────────────────────────────
var int cust_mfe25_tot = 0, var int cust_mfe25_nxt = 0, var int cust_mfe25_opp = 0
var int cust_mfe50_tot = 0, var int cust_mfe50_nxt = 0, var int cust_mfe50_opp = 0
var int cust_mfe75_tot = 0, var int cust_mfe75_nxt = 0, var int cust_mfe75_opp = 0
var int cust_mfe90_tot = 0, var int cust_mfe90_opp = 0
var int cust_mae25_tot = 0, var int cust_mae25_nxt = 0, var int cust_mae25_opp = 0
var int cust_mae50_tot = 0, var int cust_mae50_nxt = 0, var int cust_mae50_opp = 0
var int cust_mae75_tot = 0, var int cust_mae75_nxt = 0, var int cust_mae75_opp = 0
var int cust_mae90_tot = 0, var int cust_mae90_opp = 0
var int cust_sess_tot  = 0

// ─── Intra-session sequencing — bar-by-bar tracking ──────────────
// Tracks same-side retracement patterns:
//   MFE P90 hit → price retraces back below MFE P75
//   MFE P75 hit → price retraces back below MFE P50
//   MFE P50 hit → price retraces back below MFE P25
//   MAE P90 hit → price retraces back above MAE P75
//   MAE P75 hit → price retraces back above MAE P50
//   MAE P50 hit → price retraces back above MAE P25
//
// All thresholds are distances from session open (same units as mfe/mae arrays)
// Flags reset at session start, checked bar by bar, read at session end.

// ── Asia sequencing ───────────────────────────────────────────────
var float asia_thr_mfe90 = na, var float asia_thr_mfe75 = na
var float asia_thr_mfe50 = na, var float asia_thr_mfe25 = na
var float asia_thr_mae90 = na, var float asia_thr_mae75 = na
var float asia_thr_mae50 = na, var float asia_thr_mae25 = na
var bool  asia_hit_mfe90 = false, var bool  asia_ret_mfe90 = false
var bool  asia_hit_mfe75 = false, var bool  asia_ret_mfe75 = false
var bool  asia_hit_mfe50 = false, var bool  asia_ret_mfe50 = false
var bool  asia_hit_mae90 = false, var bool  asia_ret_mae90 = false
var bool  asia_hit_mae75 = false, var bool  asia_ret_mae75 = false
var bool  asia_hit_mae50 = false, var bool  asia_ret_mae50 = false

// ── London sequencing ─────────────────────────────────────────────
var float lon_thr_mfe90  = na, var float lon_thr_mfe75  = na
var float lon_thr_mfe50  = na, var float lon_thr_mfe25  = na
var float lon_thr_mae90  = na, var float lon_thr_mae75  = na
var float lon_thr_mae50  = na, var float lon_thr_mae25  = na
var bool  lon_hit_mfe90  = false, var bool  lon_ret_mfe90  = false
var bool  lon_hit_mfe75  = false, var bool  lon_ret_mfe75  = false
var bool  lon_hit_mfe50  = false, var bool  lon_ret_mfe50  = false
var bool  lon_hit_mae90  = false, var bool  lon_ret_mae90  = false
var bool  lon_hit_mae75  = false, var bool  lon_ret_mae75  = false
var bool  lon_hit_mae50  = false, var bool  lon_ret_mae50  = false

// ── NY Morning sequencing ─────────────────────────────────────────
var float nyam_thr_mfe90 = na, var float nyam_thr_mfe75 = na
var float nyam_thr_mfe50 = na, var float nyam_thr_mfe25 = na
var float nyam_thr_mae90 = na, var float nyam_thr_mae75 = na
var float nyam_thr_mae50 = na, var float nyam_thr_mae25 = na
var bool  nyam_hit_mfe90 = false, var bool  nyam_ret_mfe90 = false
var bool  nyam_hit_mfe75 = false, var bool  nyam_ret_mfe75 = false
var bool  nyam_hit_mfe50 = false, var bool  nyam_ret_mfe50 = false
var bool  nyam_hit_mae90 = false, var bool  nyam_ret_mae90 = false
var bool  nyam_hit_mae75 = false, var bool  nyam_ret_mae75 = false
var bool  nyam_hit_mae50 = false, var bool  nyam_ret_mae50 = false

// ── NY Afternoon sequencing ───────────────────────────────────────
var float nypm_thr_mfe90 = na, var float nypm_thr_mfe75 = na
var float nypm_thr_mfe50 = na, var float nypm_thr_mfe25 = na
var float nypm_thr_mae90 = na, var float nypm_thr_mae75 = na
var float nypm_thr_mae50 = na, var float nypm_thr_mae25 = na
var bool  nypm_hit_mfe90 = false, var bool  nypm_ret_mfe90 = false
var bool  nypm_hit_mfe75 = false, var bool  nypm_ret_mfe75 = false
var bool  nypm_hit_mfe50 = false, var bool  nypm_ret_mfe50 = false
var bool  nypm_hit_mae90 = false, var bool  nypm_ret_mae90 = false
var bool  nypm_hit_mae75 = false, var bool  nypm_ret_mae75 = false
var bool  nypm_hit_mae50 = false, var bool  nypm_ret_mae50 = false

// ── Custom sequencing ─────────────────────────────────────────────
var float cust_thr_mfe90 = na, var float cust_thr_mfe75 = na
var float cust_thr_mfe50 = na, var float cust_thr_mfe25 = na
var float cust_thr_mae90 = na, var float cust_thr_mae75 = na
var float cust_thr_mae50 = na, var float cust_thr_mae25 = na
var bool  cust_hit_mfe90 = false, var bool  cust_ret_mfe90 = false
var bool  cust_hit_mfe75 = false, var bool  cust_ret_mfe75 = false
var bool  cust_hit_mfe50 = false, var bool  cust_ret_mfe50 = false
var bool  cust_hit_mae90 = false, var bool  cust_ret_mae90 = false
var bool  cust_hit_mae75 = false, var bool  cust_ret_mae75 = false
var bool  cust_hit_mae50 = false, var bool  cust_ret_mae50 = false

// ─── Reset thresholds + flags at session start ────────────────────

if asia_start
    asia_thr_mfe90 := f_pct_val(asia_mfe, 90)
    asia_thr_mfe75 := f_pct_val(asia_mfe, 75)
    asia_thr_mfe50 := f_pct_val(asia_mfe, 50)
    asia_thr_mfe25 := f_pct_val(asia_mfe, 25)
    asia_thr_mae90 := f_pct_val(asia_mae, 90)
    asia_thr_mae75 := f_pct_val(asia_mae, 75)
    asia_thr_mae50 := f_pct_val(asia_mae, 50)
    asia_thr_mae25 := f_pct_val(asia_mae, 25)
    asia_hit_mfe90 := false, asia_ret_mfe90 := false
    asia_hit_mfe75 := false, asia_ret_mfe75 := false
    asia_hit_mfe50 := false, asia_ret_mfe50 := false
    asia_hit_mae90 := false, asia_ret_mae90 := false
    asia_hit_mae75 := false, asia_ret_mae75 := false
    asia_hit_mae50 := false, asia_ret_mae50 := false

if lon_start
    lon_thr_mfe90 := f_pct_val(lon_mfe, 90)
    lon_thr_mfe75 := f_pct_val(lon_mfe, 75)
    lon_thr_mfe50 := f_pct_val(lon_mfe, 50)
    lon_thr_mfe25 := f_pct_val(lon_mfe, 25)
    lon_thr_mae90 := f_pct_val(lon_mae, 90)
    lon_thr_mae75 := f_pct_val(lon_mae, 75)
    lon_thr_mae50 := f_pct_val(lon_mae, 50)
    lon_thr_mae25 := f_pct_val(lon_mae, 25)
    lon_hit_mfe90 := false, lon_ret_mfe90 := false
    lon_hit_mfe75 := false, lon_ret_mfe75 := false
    lon_hit_mfe50 := false, lon_ret_mfe50 := false
    lon_hit_mae90 := false, lon_ret_mae90 := false
    lon_hit_mae75 := false, lon_ret_mae75 := false
    lon_hit_mae50 := false, lon_ret_mae50 := false

if nyam_start
    nyam_thr_mfe90 := f_pct_val(nyam_mfe, 90)
    nyam_thr_mfe75 := f_pct_val(nyam_mfe, 75)
    nyam_thr_mfe50 := f_pct_val(nyam_mfe, 50)
    nyam_thr_mfe25 := f_pct_val(nyam_mfe, 25)
    nyam_thr_mae90 := f_pct_val(nyam_mae, 90)
    nyam_thr_mae75 := f_pct_val(nyam_mae, 75)
    nyam_thr_mae50 := f_pct_val(nyam_mae, 50)
    nyam_thr_mae25 := f_pct_val(nyam_mae, 25)
    nyam_hit_mfe90 := false, nyam_ret_mfe90 := false
    nyam_hit_mfe75 := false, nyam_ret_mfe75 := false
    nyam_hit_mfe50 := false, nyam_ret_mfe50 := false
    nyam_hit_mae90 := false, nyam_ret_mae90 := false
    nyam_hit_mae75 := false, nyam_ret_mae75 := false
    nyam_hit_mae50 := false, nyam_ret_mae50 := false

if nypm_start
    nypm_thr_mfe90 := f_pct_val(nypm_mfe, 90)
    nypm_thr_mfe75 := f_pct_val(nypm_mfe, 75)
    nypm_thr_mfe50 := f_pct_val(nypm_mfe, 50)
    nypm_thr_mfe25 := f_pct_val(nypm_mfe, 25)
    nypm_thr_mae90 := f_pct_val(nypm_mae, 90)
    nypm_thr_mae75 := f_pct_val(nypm_mae, 75)
    nypm_thr_mae50 := f_pct_val(nypm_mae, 50)
    nypm_thr_mae25 := f_pct_val(nypm_mae, 25)
    nypm_hit_mfe90 := false, nypm_ret_mfe90 := false
    nypm_hit_mfe75 := false, nypm_ret_mfe75 := false
    nypm_hit_mfe50 := false, nypm_ret_mfe50 := false
    nypm_hit_mae90 := false, nypm_ret_mae90 := false
    nypm_hit_mae75 := false, nypm_ret_mae75 := false
    nypm_hit_mae50 := false, nypm_ret_mae50 := false

if cust_start
    cust_thr_mfe90 := f_pct_val(cust_mfe, 90)
    cust_thr_mfe75 := f_pct_val(cust_mfe, 75)
    cust_thr_mfe50 := f_pct_val(cust_mfe, 50)
    cust_thr_mfe25 := f_pct_val(cust_mfe, 25)
    cust_thr_mae90 := f_pct_val(cust_mae, 90)
    cust_thr_mae75 := f_pct_val(cust_mae, 75)
    cust_thr_mae50 := f_pct_val(cust_mae, 50)
    cust_thr_mae25 := f_pct_val(cust_mae, 25)
    cust_hit_mfe90 := false, cust_ret_mfe90 := false
    cust_hit_mfe75 := false, cust_ret_mfe75 := false
    cust_hit_mfe50 := false, cust_ret_mfe50 := false
    cust_hit_mae90 := false, cust_ret_mae90 := false
    cust_hit_mae75 := false, cust_ret_mae75 := false
    cust_hit_mae50 := false, cust_ret_mae50 := false

// ─── Bar-by-bar sequencing checks (inline, no function) ──────────

if in_asia and not na(asia_o)
    _du = high  - asia_o
    _dd = asia_o - low
    _cl = close - asia_o
    if not na(asia_thr_mfe90) and _du >= asia_thr_mfe90
        asia_hit_mfe90 := true
    if not na(asia_thr_mfe75) and _du >= asia_thr_mfe75
        asia_hit_mfe75 := true
    if not na(asia_thr_mfe50) and _du >= asia_thr_mfe50
        asia_hit_mfe50 := true
    if asia_hit_mfe90 and not na(asia_thr_mfe75) and _cl < asia_thr_mfe75
        asia_ret_mfe90 := true
    if asia_hit_mfe75 and not na(asia_thr_mfe50) and _cl < asia_thr_mfe50
        asia_ret_mfe75 := true
    if asia_hit_mfe50 and not na(asia_thr_mfe25) and _cl < asia_thr_mfe25
        asia_ret_mfe50 := true
    if not na(asia_thr_mae90) and _dd >= asia_thr_mae90
        asia_hit_mae90 := true
    if not na(asia_thr_mae75) and _dd >= asia_thr_mae75
        asia_hit_mae75 := true
    if not na(asia_thr_mae50) and _dd >= asia_thr_mae50
        asia_hit_mae50 := true
    if asia_hit_mae90 and not na(asia_thr_mae75) and (asia_o - close) < asia_thr_mae75
        asia_ret_mae90 := true
    if asia_hit_mae75 and not na(asia_thr_mae50) and (asia_o - close) < asia_thr_mae50
        asia_ret_mae75 := true
    if asia_hit_mae50 and not na(asia_thr_mae25) and (asia_o - close) < asia_thr_mae25
        asia_ret_mae50 := true

if in_lon and not na(lon_o)
    _du = high  - lon_o
    _dd = lon_o - low
    _cl = close - lon_o
    if not na(lon_thr_mfe90) and _du >= lon_thr_mfe90
        lon_hit_mfe90 := true
    if not na(lon_thr_mfe75) and _du >= lon_thr_mfe75
        lon_hit_mfe75 := true
    if not na(lon_thr_mfe50) and _du >= lon_thr_mfe50
        lon_hit_mfe50 := true
    if lon_hit_mfe90 and not na(lon_thr_mfe75) and _cl < lon_thr_mfe75
        lon_ret_mfe90 := true
    if lon_hit_mfe75 and not na(lon_thr_mfe50) and _cl < lon_thr_mfe50
        lon_ret_mfe75 := true
    if lon_hit_mfe50 and not na(lon_thr_mfe25) and _cl < lon_thr_mfe25
        lon_ret_mfe50 := true
    if not na(lon_thr_mae90) and _dd >= lon_thr_mae90
        lon_hit_mae90 := true
    if not na(lon_thr_mae75) and _dd >= lon_thr_mae75
        lon_hit_mae75 := true
    if not na(lon_thr_mae50) and _dd >= lon_thr_mae50
        lon_hit_mae50 := true
    if lon_hit_mae90 and not na(lon_thr_mae75) and (lon_o - close) < lon_thr_mae75
        lon_ret_mae90 := true
    if lon_hit_mae75 and not na(lon_thr_mae50) and (lon_o - close) < lon_thr_mae50
        lon_ret_mae75 := true
    if lon_hit_mae50 and not na(lon_thr_mae25) and (lon_o - close) < lon_thr_mae25
        lon_ret_mae50 := true

if in_nyam and not na(nyam_o)
    _du = high  - nyam_o
    _dd = nyam_o - low
    _cl = close - nyam_o
    if not na(nyam_thr_mfe90) and _du >= nyam_thr_mfe90
        nyam_hit_mfe90 := true
    if not na(nyam_thr_mfe75) and _du >= nyam_thr_mfe75
        nyam_hit_mfe75 := true
    if not na(nyam_thr_mfe50) and _du >= nyam_thr_mfe50
        nyam_hit_mfe50 := true
    if nyam_hit_mfe90 and not na(nyam_thr_mfe75) and _cl < nyam_thr_mfe75
        nyam_ret_mfe90 := true
    if nyam_hit_mfe75 and not na(nyam_thr_mfe50) and _cl < nyam_thr_mfe50
        nyam_ret_mfe75 := true
    if nyam_hit_mfe50 and not na(nyam_thr_mfe25) and _cl < nyam_thr_mfe25
        nyam_ret_mfe50 := true
    if not na(nyam_thr_mae90) and _dd >= nyam_thr_mae90
        nyam_hit_mae90 := true
    if not na(nyam_thr_mae75) and _dd >= nyam_thr_mae75
        nyam_hit_mae75 := true
    if not na(nyam_thr_mae50) and _dd >= nyam_thr_mae50
        nyam_hit_mae50 := true
    if nyam_hit_mae90 and not na(nyam_thr_mae75) and (nyam_o - close) < nyam_thr_mae75
        nyam_ret_mae90 := true
    if nyam_hit_mae75 and not na(nyam_thr_mae50) and (nyam_o - close) < nyam_thr_mae50
        nyam_ret_mae75 := true
    if nyam_hit_mae50 and not na(nyam_thr_mae25) and (nyam_o - close) < nyam_thr_mae25
        nyam_ret_mae50 := true

if in_nypm and not na(nypm_o)
    _du = high  - nypm_o
    _dd = nypm_o - low
    _cl = close - nypm_o
    if not na(nypm_thr_mfe90) and _du >= nypm_thr_mfe90
        nypm_hit_mfe90 := true
    if not na(nypm_thr_mfe75) and _du >= nypm_thr_mfe75
        nypm_hit_mfe75 := true
    if not na(nypm_thr_mfe50) and _du >= nypm_thr_mfe50
        nypm_hit_mfe50 := true
    if nypm_hit_mfe90 and not na(nypm_thr_mfe75) and _cl < nypm_thr_mfe75
        nypm_ret_mfe90 := true
    if nypm_hit_mfe75 and not na(nypm_thr_mfe50) and _cl < nypm_thr_mfe50
        nypm_ret_mfe75 := true
    if nypm_hit_mfe50 and not na(nypm_thr_mfe25) and _cl < nypm_thr_mfe25
        nypm_ret_mfe50 := true
    if not na(nypm_thr_mae90) and _dd >= nypm_thr_mae90
        nypm_hit_mae90 := true
    if not na(nypm_thr_mae75) and _dd >= nypm_thr_mae75
        nypm_hit_mae75 := true
    if not na(nypm_thr_mae50) and _dd >= nypm_thr_mae50
        nypm_hit_mae50 := true
    if nypm_hit_mae90 and not na(nypm_thr_mae75) and (nypm_o - close) < nypm_thr_mae75
        nypm_ret_mae90 := true
    if nypm_hit_mae75 and not na(nypm_thr_mae50) and (nypm_o - close) < nypm_thr_mae50
        nypm_ret_mae75 := true
    if nypm_hit_mae50 and not na(nypm_thr_mae25) and (nypm_o - close) < nypm_thr_mae25
        nypm_ret_mae50 := true

if in_cust and not na(cust_o)
    _du = high  - cust_o
    _dd = cust_o - low
    _cl = close - cust_o
    if not na(cust_thr_mfe90) and _du >= cust_thr_mfe90
        cust_hit_mfe90 := true
    if not na(cust_thr_mfe75) and _du >= cust_thr_mfe75
        cust_hit_mfe75 := true
    if not na(cust_thr_mfe50) and _du >= cust_thr_mfe50
        cust_hit_mfe50 := true
    if cust_hit_mfe90 and not na(cust_thr_mfe75) and _cl < cust_thr_mfe75
        cust_ret_mfe90 := true
    if cust_hit_mfe75 and not na(cust_thr_mfe50) and _cl < cust_thr_mfe50
        cust_ret_mfe75 := true
    if cust_hit_mfe50 and not na(cust_thr_mfe25) and _cl < cust_thr_mfe25
        cust_ret_mfe50 := true
    if not na(cust_thr_mae90) and _dd >= cust_thr_mae90
        cust_hit_mae90 := true
    if not na(cust_thr_mae75) and _dd >= cust_thr_mae75
        cust_hit_mae75 := true
    if not na(cust_thr_mae50) and _dd >= cust_thr_mae50
        cust_hit_mae50 := true
    if cust_hit_mae90 and not na(cust_thr_mae75) and (cust_o - close) < cust_thr_mae75
        cust_ret_mae90 := true
    if cust_hit_mae75 and not na(cust_thr_mae50) and (cust_o - close) < cust_thr_mae50
        cust_ret_mae75 := true
    if cust_hit_mae50 and not na(cust_thr_mae25) and (cust_o - close) < cust_thr_mae25
        cust_ret_mae50 := true

// ─── f_record_session ─────────────────────────────────────────────
// Called at session end with all OHLC values.
// 1. Computes mfe/mae/rng/cls and pushes to arrays (trimmed to 100)
// 2. Splits into bull/bear directional arrays
// 3. Determines if session "reverted" (close within cls P25-P75)
// 4. Returns 22 counter deltas:
//    [mfe25_t, mfe25_r, mfe25_nxt,
//     mfe50_t, mfe50_r, mfe50_nxt,
//     mfe75_t, mfe75_r, mfe75_nxt,
//     mfe90_t, mfe90_r,
//     mae25_t, mae25_r, mae25_nxt,
//     mae50_t, mae50_r, mae50_nxt,
//     mae75_t, mae75_r, mae75_nxt,
//     mae90_t, mae90_r]

f_record_session(rng_a, mfe_a, mae_a,
                 bull_mfe_a, bull_mae_a,
                 bear_mfe_a, bear_mae_a,
                 cls_a,
                 s_open, s_high, s_low, s_close,
                 hit_mfe90, ret_mfe90,
                 hit_mfe75, ret_mfe75,
                 hit_mfe50, ret_mfe50,
                 hit_mae90, ret_mae90,
                 hit_mae75, ret_mae75,
                 hit_mae50, ret_mae50) =>

    mfe = s_high - s_open   // max upside from open
    mae = s_open - s_low    // max downside from open
    rng = s_high - s_low
    cls = s_close - s_open  // signed close deviation
    is_bull = s_close >= s_open

    // Push to combined arrays
    array.push(rng_a, rng)
    array.push(mfe_a, mfe)
    array.push(mae_a, mae)
    array.push(cls_a, cls)

    // Push to directional arrays
    if is_bull
        array.push(bull_mfe_a, mfe)
        array.push(bull_mae_a, mae)
    else
        array.push(bear_mfe_a, mfe)
        array.push(bear_mae_a, mae)

    // Trim all arrays to 100 sessions
    if array.size(rng_a)      > 100
        array.shift(rng_a)
    if array.size(mfe_a)      > 100
        array.shift(mfe_a)
    if array.size(mae_a)      > 100
        array.shift(mae_a)
    if array.size(cls_a)      > 100
        array.shift(cls_a)
    if array.size(bull_mfe_a) > 100
        array.shift(bull_mfe_a)
    if array.size(bull_mae_a) > 100
        array.shift(bull_mae_a)
    if array.size(bear_mfe_a) > 100
        array.shift(bear_mfe_a)
    if array.size(bear_mae_a) > 100
        array.shift(bear_mae_a)

    // MFE level thresholds
    mfe_p25 = array.size(mfe_a) >= 5 ? array.percentile_nearest_rank(mfe_a, 25) : float(na)
    mfe_p50 = array.size(mfe_a) >= 5 ? array.percentile_nearest_rank(mfe_a, 50) : float(na)
    mfe_p75 = array.size(mfe_a) >= 5 ? array.percentile_nearest_rank(mfe_a, 75) : float(na)
    mfe_p90 = array.size(mfe_a) >= 5 ? array.percentile_nearest_rank(mfe_a, 90) : float(na)

    // MAE level thresholds
    mae_p25 = array.size(mae_a) >= 5 ? array.percentile_nearest_rank(mae_a, 25) : float(na)
    mae_p50 = array.size(mae_a) >= 5 ? array.percentile_nearest_rank(mae_a, 50) : float(na)
    mae_p75 = array.size(mae_a) >= 5 ? array.percentile_nearest_rank(mae_a, 75) : float(na)
    mae_p90 = array.size(mae_a) >= 5 ? array.percentile_nearest_rank(mae_a, 90) : float(na)

    // MFE counter deltas
    mfe25_t = not na(mfe_p25) and mfe >= mfe_p25 ? 1 : 0
    mfe50_t = not na(mfe_p50) and mfe >= mfe_p50 ? 1 : 0
    mfe75_t = not na(mfe_p75) and mfe >= mfe_p75 ? 1 : 0
    mfe90_t = not na(mfe_p90) and mfe >= mfe_p90 ? 1 : 0

    // MAE counter deltas
    mae25_t = not na(mae_p25) and mae >= mae_p25 ? 1 : 0
    mae50_t = not na(mae_p50) and mae >= mae_p50 ? 1 : 0
    mae75_t = not na(mae_p75) and mae >= mae_p75 ? 1 : 0
    mae90_t = not na(mae_p90) and mae >= mae_p90 ? 1 : 0

    // Next-level deltas — reached this level AND the next level in same direction
    mfe25_nxt = mfe25_t == 1 and mfe50_t == 1 ? 1 : 0
    mfe50_nxt = mfe50_t == 1 and mfe75_t == 1 ? 1 : 0
    mfe75_nxt = mfe75_t == 1 and mfe90_t == 1 ? 1 : 0
    mae25_nxt = mae25_t == 1 and mae50_t == 1 ? 1 : 0
    mae50_nxt = mae50_t == 1 and mae75_t == 1 ? 1 : 0
    mae75_nxt = mae75_t == 1 and mae90_t == 1 ? 1 : 0

    // Opposite-direction sequenced deltas
    // hit_mfe75 then hit_mae25_seq = price went to MFE P75 THEN reversed to MAE P25
    // hit_mae75 then hit_mfe25_seq = price went to MAE P75 THEN reversed to MFE P25
    // Same-side retrace deltas — after hitting level, did price retrace to level below?
    mfe25_opp = 0
    mfe50_opp = mfe50_t == 1 and ret_mfe50 ? 1 : 0
    mfe75_opp = mfe75_t == 1 and ret_mfe75 ? 1 : 0
    mfe90_opp = mfe90_t == 1 and ret_mfe90 ? 1 : 0
    mae25_opp = 0
    mae50_opp = mae50_t == 1 and ret_mae50 ? 1 : 0
    mae75_opp = mae75_t == 1 and ret_mae75 ? 1 : 0
    mae90_opp = mae90_t == 1 and ret_mae90 ? 1 : 0

    [mfe25_t, mfe25_nxt, mfe25_opp,
     mfe50_t, mfe50_nxt, mfe50_opp,
     mfe75_t, mfe75_nxt, mfe75_opp,
     mfe90_t, mfe90_opp,
     mae25_t, mae25_nxt, mae25_opp,
     mae50_t, mae50_nxt, mae50_opp,
     mae75_t, mae75_nxt, mae75_opp,
     mae90_t, mae90_opp]

// ─── Call f_record_session at each session end ────────────────────

if asia_end and not na(asia_o) and asia_o != 0
    [a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22] =
         f_record_session(asia_rng, asia_mfe, asia_mae,
                          asia_bull_mfe, asia_bull_mae,
                          asia_bear_mfe, asia_bear_mae,
                          asia_cls, asia_o, asia_h, asia_l, close[1],
                          asia_hit_mfe90, asia_ret_mfe90,
                          asia_hit_mfe75, asia_ret_mfe75,
                          asia_hit_mfe50, asia_ret_mfe50,
                          asia_hit_mae90, asia_ret_mae90,
                          asia_hit_mae75, asia_ret_mae75,
                          asia_hit_mae50, asia_ret_mae50)
    asia_sess_tot += 1
    if close[1] >= asia_o
        asia_bull_ct += 1
    else
        asia_bear_ct += 1
    asia_mfe25_tot += a1,  asia_mfe25_nxt += a2,  asia_mfe25_opp += a3
    asia_mfe50_tot += a4,  asia_mfe50_nxt += a5,  asia_mfe50_opp += a6
    asia_mfe75_tot += a7,  asia_mfe75_nxt += a8,  asia_mfe75_opp += a9
    asia_mfe90_tot += a10, asia_mfe90_opp += a11
    asia_mae25_tot += a12, asia_mae25_nxt += a13, asia_mae25_opp += a14
    asia_mae50_tot += a15, asia_mae50_nxt += a16, asia_mae50_opp += a17
    asia_mae75_tot += a18, asia_mae75_nxt += a19, asia_mae75_opp += a20
    asia_mae90_tot += a21, asia_mae90_opp += a22

if lon_end and not na(lon_o) and lon_o != 0
    [a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22] =
         f_record_session(lon_rng, lon_mfe, lon_mae,
                          lon_bull_mfe, lon_bull_mae,
                          lon_bear_mfe, lon_bear_mae,
                          lon_cls, lon_o, lon_h, lon_l, close[1],
                          lon_hit_mfe90, lon_ret_mfe90,
                          lon_hit_mfe75, lon_ret_mfe75,
                          lon_hit_mfe50, lon_ret_mfe50,
                          lon_hit_mae90, lon_ret_mae90,
                          lon_hit_mae75, lon_ret_mae75,
                          lon_hit_mae50, lon_ret_mae50)
    lon_sess_tot += 1
    if close[1] >= lon_o
        lon_bull_ct += 1
    else
        lon_bear_ct += 1
    lon_mfe25_tot += a1,  lon_mfe25_nxt += a2,  lon_mfe25_opp += a3
    lon_mfe50_tot += a4,  lon_mfe50_nxt += a5,  lon_mfe50_opp += a6
    lon_mfe75_tot += a7,  lon_mfe75_nxt += a8,  lon_mfe75_opp += a9
    lon_mfe90_tot += a10, lon_mfe90_opp += a11
    lon_mae25_tot += a12, lon_mae25_nxt += a13, lon_mae25_opp += a14
    lon_mae50_tot += a15, lon_mae50_nxt += a16, lon_mae50_opp += a17
    lon_mae75_tot += a18, lon_mae75_nxt += a19, lon_mae75_opp += a20
    lon_mae90_tot += a21, lon_mae90_opp += a22

if nyam_end and not na(nyam_o) and nyam_o != 0
    [a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22] =
         f_record_session(nyam_rng, nyam_mfe, nyam_mae,
                          nyam_bull_mfe, nyam_bull_mae,
                          nyam_bear_mfe, nyam_bear_mae,
                          nyam_cls, nyam_o, nyam_h, nyam_l, close[1],
                          nyam_hit_mfe90, nyam_ret_mfe90,
                          nyam_hit_mfe75, nyam_ret_mfe75,
                          nyam_hit_mfe50, nyam_ret_mfe50,
                          nyam_hit_mae90, nyam_ret_mae90,
                          nyam_hit_mae75, nyam_ret_mae75,
                          nyam_hit_mae50, nyam_ret_mae50)
    nyam_sess_tot += 1
    if close[1] >= nyam_o
        nyam_bull_ct += 1
    else
        nyam_bear_ct += 1
    nyam_mfe25_tot += a1,  nyam_mfe25_nxt += a2,  nyam_mfe25_opp += a3
    nyam_mfe50_tot += a4,  nyam_mfe50_nxt += a5,  nyam_mfe50_opp += a6
    nyam_mfe75_tot += a7,  nyam_mfe75_nxt += a8,  nyam_mfe75_opp += a9
    nyam_mfe90_tot += a10, nyam_mfe90_opp += a11
    nyam_mae25_tot += a12, nyam_mae25_nxt += a13, nyam_mae25_opp += a14
    nyam_mae50_tot += a15, nyam_mae50_nxt += a16, nyam_mae50_opp += a17
    nyam_mae75_tot += a18, nyam_mae75_nxt += a19, nyam_mae75_opp += a20
    nyam_mae90_tot += a21, nyam_mae90_opp += a22

if nypm_end and not na(nypm_o) and nypm_o != 0
    [a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22] =
         f_record_session(nypm_rng, nypm_mfe, nypm_mae,
                          nypm_bull_mfe, nypm_bull_mae,
                          nypm_bear_mfe, nypm_bear_mae,
                          nypm_cls, nypm_o, nypm_h, nypm_l, close[1],
                          nypm_hit_mfe90, nypm_ret_mfe90,
                          nypm_hit_mfe75, nypm_ret_mfe75,
                          nypm_hit_mfe50, nypm_ret_mfe50,
                          nypm_hit_mae90, nypm_ret_mae90,
                          nypm_hit_mae75, nypm_ret_mae75,
                          nypm_hit_mae50, nypm_ret_mae50)
    nypm_sess_tot += 1
    if close[1] >= nypm_o
        nypm_bull_ct += 1
    else
        nypm_bear_ct += 1
    nypm_mfe25_tot += a1,  nypm_mfe25_nxt += a2,  nypm_mfe25_opp += a3
    nypm_mfe50_tot += a4,  nypm_mfe50_nxt += a5,  nypm_mfe50_opp += a6
    nypm_mfe75_tot += a7,  nypm_mfe75_nxt += a8,  nypm_mfe75_opp += a9
    nypm_mfe90_tot += a10, nypm_mfe90_opp += a11
    nypm_mae25_tot += a12, nypm_mae25_nxt += a13, nypm_mae25_opp += a14
    nypm_mae50_tot += a15, nypm_mae50_nxt += a16, nypm_mae50_opp += a17
    nypm_mae75_tot += a18, nypm_mae75_nxt += a19, nypm_mae75_opp += a20
    nypm_mae90_tot += a21, nypm_mae90_opp += a22

if cust_end and not na(cust_o) and cust_o != 0
    [a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22] =
         f_record_session(cust_rng, cust_mfe, cust_mae,
                          cust_bull_mfe, cust_bull_mae,
                          cust_bear_mfe, cust_bear_mae,
                          cust_cls, cust_o, cust_h, cust_l, close[1],
                          cust_hit_mfe90, cust_ret_mfe90,
                          cust_hit_mfe75, cust_ret_mfe75,
                          cust_hit_mfe50, cust_ret_mfe50,
                          cust_hit_mae90, cust_ret_mae90,
                          cust_hit_mae75, cust_ret_mae75,
                          cust_hit_mae50, cust_ret_mae50)
    cust_sess_tot += 1
    if close[1] >= cust_o
        cust_bull_ct += 1
    else
        cust_bear_ct += 1
    cust_mfe25_tot += a1,  cust_mfe25_nxt += a2,  cust_mfe25_opp += a3
    cust_mfe50_tot += a4,  cust_mfe50_nxt += a5,  cust_mfe50_opp += a6
    cust_mfe75_tot += a7,  cust_mfe75_nxt += a8,  cust_mfe75_opp += a9
    cust_mfe90_tot += a10, cust_mfe90_opp += a11
    cust_mae25_tot += a12, cust_mae25_nxt += a13, cust_mae25_opp += a14
    cust_mae50_tot += a15, cust_mae50_nxt += a16, cust_mae50_opp += a17
    cust_mae75_tot += a18, cust_mae75_nxt += a19, cust_mae75_opp += a20
    cust_mae90_tot += a21, cust_mae90_opp += a22

// ═══════════════════════════════════════════════════════════════════
// SECTION 7 — LIVE SCORING
// Computes on every bar:
//   curr_sess     : which session is active
//   curr_open     : session open price
//   curr_dist     : signed distance from open in points
//   curr_pct_rank : percentile of current excursion vs history
//                   (vs MFE array if above open, MAE if below)
// ═══════════════════════════════════════════════════════════════════

curr_sess =
     in_asia ? "ASIA" :
     in_lon  ? "LON"  :
     in_nyam ? "NYAM" :
     in_nypm ? "NYPM" :
     in_cust ? "CUST" : ""

curr_open =
     in_asia ? asia_o :
     in_lon  ? lon_o  :
     in_nyam ? nyam_o :
     in_nypm ? nypm_o :
     in_cust ? cust_o : float(na)

curr_dist = not na(curr_open) ? close - curr_open : float(na)

curr_mfe_arr =
     in_asia ? asia_mfe :
     in_lon  ? lon_mfe  :
     in_nyam ? nyam_mfe :
     in_nypm ? nypm_mfe :
     in_cust ? cust_mfe : array.new_float(0)

curr_mae_arr =
     in_asia ? asia_mae :
     in_lon  ? lon_mae  :
     in_nyam ? nyam_mae :
     in_nypm ? nypm_mae :
     in_cust ? cust_mae : array.new_float(0)

curr_excursion  = not na(curr_dist) ? math.abs(curr_dist) : float(na)
curr_score_arr  = not na(curr_dist) and curr_dist >= 0 ? curr_mfe_arr : curr_mae_arr
curr_pct_rank   = not na(curr_excursion) and array.size(curr_score_arr) >= 5 ?
     f_pct_rank(curr_score_arr, curr_excursion) : int(na)

// ═══════════════════════════════════════════════════════════════════
// SECTION 8 — BAND PLOTTING
//
// Three layers per session:
//   A) Session open line  — dashed, session colour
//   B) Range bands        — symmetric H-L percentile offsets from open
//                           style/colour from Range Band inputs
//   C) MFE/MAE bands      — directional excursion offsets from open
//                           optionally split bull/bear
//                           style/colour from MFE/MAE inputs
//
// All objects drawn at session start, extended every bar, cleared
// when the next session begins.
// Labels track the right edge via label.set_x() every bar.
// ═══════════════════════════════════════════════════════════════════

// ─── Per-session object stores ────────────────────────────────────
// We use arrays of lines/labels/boxes so any number of levels
// can be added dynamically without declaring every object up front.

var line[]  asia_lines  = array.new_line()
var label[] asia_labels = array.new_label()
var box[]   asia_boxes  = array.new_box()
var line    asia_oline  = na   // session open line

var line[]  lon_lines   = array.new_line()
var label[] lon_labels  = array.new_label()
var box[]   lon_boxes   = array.new_box()
var line    lon_oline   = na

var line[]  nyam_lines  = array.new_line()
var label[] nyam_labels = array.new_label()
var box[]   nyam_boxes  = array.new_box()
var line    nyam_oline  = na

var line[]  nypm_lines  = array.new_line()
var label[] nypm_labels = array.new_label()
var box[]   nypm_boxes  = array.new_box()
var line    nypm_oline  = na

var line[]  cust_lines  = array.new_line()
var label[] cust_labels = array.new_label()
var box[]   cust_boxes  = array.new_box()
var line    cust_oline  = na

// ─── Clear / extend helpers ───────────────────────────────────────

f_clear(lns, lbs, bxs) =>
    for ln in lns
        line.delete(ln)
    array.clear(lns)
    for lb in lbs
        label.delete(lb)
    array.clear(lbs)
    for bx in bxs
        box.delete(bx)
    array.clear(bxs)

f_extend(lns, lbs, bxs) =>
    x2 = bar_index + i_proj_bars
    for ln in lns
        line.set_x2(ln, x2)
    for lb in lbs
        label.set_x(lb, x2)
    for bx in bxs
        box.set_right(bx, x2)

// ─── Add a single level line + label ─────────────────────────────

f_add_level(lns, lbs, x1, y, txt, col, ls, lw) =>
    array.push(lns, line.new(x1, y, x1 + 1, y,
         color=col, style=ls, width=lw))
    array.push(lbs, label.new(x1 + 1, y, " " + txt,
         style=label.style_none, textcolor=color.new(col, 30),
         color=color.new(color.white, 100),
         size=f_lbl_size(), text_font_family=font.family_monospace))

// ─── Add a band (two lines + optional fill box) ───────────────────

f_add_band(lns, lbs, bxs, x1, y_hi, y_lo, txt_hi, txt_lo, col, ls, lw) =>
    array.push(lns, line.new(x1, y_hi, x1 + 1, y_hi,
         color=col, style=ls, width=lw))
    array.push(lns, line.new(x1, y_lo, x1 + 1, y_lo,
         color=col, style=ls, width=lw))
    array.push(lbs, label.new(x1 + 1, y_hi, " " + txt_hi,
         style=label.style_none, textcolor=color.new(col, 30),
         color=color.new(color.white, 100),
         size=f_lbl_size(), text_font_family=font.family_monospace))
    array.push(lbs, label.new(x1 + 1, y_lo, " " + txt_lo,
         style=label.style_none, textcolor=color.new(col, 30),
         color=color.new(color.white, 100),
         size=f_lbl_size(), text_font_family=font.family_monospace))
    if i_rng_fills
        array.push(bxs, box.new(x1, y_hi, x1 + 1, y_lo,
             bgcolor=color.new(col, 93), border_width=0))

// ─── Draw all bands for one session ──────────────────────────────
// Called once at session start. Draws range bands then MFE/MAE bands.

f_draw_bands(lns, lbs, bxs, x1, s_open, slbl, col,
              rng_a, mfe_a, mae_a,
              bull_mfe_a, bull_mae_a,
              bear_mfe_a, bear_mae_a) =>

    rng_ls  = f_line_style(i_rng_style)
    exc_ls  = f_line_style(i_exc_style)

    // ── A) Range bands (symmetric, H-L percentiles) ──────────────
    if array.size(rng_a) >= 5

        p10 = f_pct_val(rng_a, 10)
        p25 = f_pct_val(rng_a, 25)
        p50 = f_pct_val(rng_a, 50)
        p75 = f_pct_val(rng_a, 75)
        p90 = f_pct_val(rng_a, 90)
        avg = array.size(rng_a) >= 2 ? array.avg(rng_a) : float(na)

        if i_rng_p10p90 and not na(p90)
            f_add_band(lns, lbs, bxs, x1,
                 s_open + p90, s_open - p90,
                 slbl + " P90", slbl + " -P90",
                 i_col_p10p90, rng_ls, i_rng_width)
        if i_rng_p10p90 and not na(p10)
            f_add_band(lns, lbs, bxs, x1,
                 s_open + p10, s_open - p10,
                 slbl + " P10", slbl + " -P10",
                 i_col_p10p90, rng_ls, i_rng_width)
        if i_rng_iqr and not na(p75)
            f_add_band(lns, lbs, bxs, x1,
                 s_open + p75, s_open - p75,
                 slbl + " P75", slbl + " -P75",
                 i_col_iqr, rng_ls, i_rng_width)
        if i_rng_iqr and not na(p25)
            f_add_band(lns, lbs, bxs, x1,
                 s_open + p25, s_open - p25,
                 slbl + " P25", slbl + " -P25",
                 i_col_iqr, rng_ls, i_rng_width)
        if i_rng_p50 and not na(p50)
            f_add_level(lns, lbs, x1, s_open + p50,
                 slbl + " P50",  i_col_p50, line.style_dashed, i_rng_width)
            f_add_level(lns, lbs, x1, s_open - p50,
                 slbl + " -P50", i_col_p50, line.style_dashed, i_rng_width)
        if i_rng_mean and not na(avg)
            f_add_level(lns, lbs, x1, s_open + avg,
                 slbl + " Mean",  i_col_mean, line.style_dashed, i_rng_width)
            f_add_level(lns, lbs, x1, s_open - avg,
                 slbl + " -Mean", i_col_mean, line.style_dashed, i_rng_width)

    // ── B) MFE / MAE bands (directional excursion) ───────────────
    if i_show_exc

        if i_bull_bear
            // Bull session MFE (upside) levels
            if array.size(bull_mfe_a) >= 5
                for p in array.from(25, 50, 75, 90)
                    v = f_pct_val(bull_mfe_a, p)
                    if not na(v)
                        f_add_level(lns, lbs, x1, s_open + v,
                             slbl + " Bull MFE" + str.tostring(p),
                             i_col_mfe, exc_ls, i_exc_width)
            // Bull session MAE (downside) levels
            if array.size(bull_mae_a) >= 5
                for p in array.from(25, 50, 75, 90)
                    v = f_pct_val(bull_mae_a, p)
                    if not na(v)
                        f_add_level(lns, lbs, x1, s_open - v,
                             slbl + " Bull MAE" + str.tostring(p),
                             i_col_mae, exc_ls, i_exc_width)
            // Bear session MFE (downside) levels
            if array.size(bear_mfe_a) >= 5
                for p in array.from(25, 50, 75, 90)
                    v = f_pct_val(bear_mfe_a, p)
                    if not na(v)
                        f_add_level(lns, lbs, x1, s_open - v,
                             slbl + " Bear MFE" + str.tostring(p),
                             i_col_mfe, exc_ls, i_exc_width)
            // Bear session MAE (upside) levels
            if array.size(bear_mae_a) >= 5
                for p in array.from(25, 50, 75, 90)
                    v = f_pct_val(bear_mae_a, p)
                    if not na(v)
                        f_add_level(lns, lbs, x1, s_open + v,
                             slbl + " Bear MAE" + str.tostring(p),
                             i_col_mae, exc_ls, i_exc_width)
        else
            // Combined MFE (above open)
            if array.size(mfe_a) >= 5
                for p in array.from(25, 50, 75, 90)
                    v = f_pct_val(mfe_a, p)
                    if not na(v)
                        f_add_level(lns, lbs, x1, s_open + v,
                             slbl + " MFE" + str.tostring(p),
                             i_col_mfe, exc_ls, i_exc_width)
            // Combined MAE (below open)
            if array.size(mae_a) >= 5
                for p in array.from(25, 50, 75, 90)
                    v = f_pct_val(mae_a, p)
                    if not na(v)
                        f_add_level(lns, lbs, x1, s_open - v,
                             slbl + " MAE" + str.tostring(p),
                             i_col_mae, exc_ls, i_exc_width)

// ─── Session open line helper ─────────────────────────────────────

f_open_line(s_open, col) =>
    line.new(bar_index, s_open, bar_index + 1, s_open,
         color=col, style=line.style_dashed, width=1)

f_open_label(s_open, txt, col) =>
    label.new(bar_index + i_proj_bars, s_open, " " + txt,
         style=label.style_none, textcolor=col,
         color=color.new(color.white, 100),
         size=f_lbl_size(), text_font_family=font.family_monospace)

// ─── Draw / clear / extend triggers ──────────────────────────────
// Simple pattern: each session clears and redraws its own bands at
// start, extends while active. Matches Document 5 working version.

// Asia
if asia_start and i_show_asia
    f_clear(asia_lines, asia_labels, asia_boxes)
    if not na(asia_oline)
        line.delete(asia_oline)
    asia_oline := f_open_line(open, i_col_asia)
    f_open_label(open, "Asia Open", i_col_asia)
    f_draw_bands(asia_lines, asia_labels, asia_boxes,
                 bar_index, open, "Asia", i_col_asia,
                 asia_rng, asia_mfe, asia_mae,
                 asia_bull_mfe, asia_bull_mae,
                 asia_bear_mfe, asia_bear_mae)

if in_asia and i_show_asia
    if not na(asia_oline)
        line.set_x2(asia_oline, bar_index + i_proj_bars)
    f_extend(asia_lines, asia_labels, asia_boxes)

// London
if lon_start and i_show_lon
    f_clear(lon_lines, lon_labels, lon_boxes)
    if not na(lon_oline)
        line.delete(lon_oline)
    lon_oline := f_open_line(open, i_col_lon)
    f_open_label(open, "London Open", i_col_lon)
    f_draw_bands(lon_lines, lon_labels, lon_boxes,
                 bar_index, open, "Lon", i_col_lon,
                 lon_rng, lon_mfe, lon_mae,
                 lon_bull_mfe, lon_bull_mae,
                 lon_bear_mfe, lon_bear_mae)

if in_lon and i_show_lon
    if not na(lon_oline)
        line.set_x2(lon_oline, bar_index + i_proj_bars)
    f_extend(lon_lines, lon_labels, lon_boxes)

// NY Morning
if nyam_start and i_show_nyam
    f_clear(nyam_lines, nyam_labels, nyam_boxes)
    if not na(nyam_oline)
        line.delete(nyam_oline)
    nyam_oline := f_open_line(open, i_col_nyam)
    f_open_label(open, "NY Morning Open", i_col_nyam)
    f_draw_bands(nyam_lines, nyam_labels, nyam_boxes,
                 bar_index, open, "NYAM", i_col_nyam,
                 nyam_rng, nyam_mfe, nyam_mae,
                 nyam_bull_mfe, nyam_bull_mae,
                 nyam_bear_mfe, nyam_bear_mae)

if in_nyam and i_show_nyam
    if not na(nyam_oline)
        line.set_x2(nyam_oline, bar_index + i_proj_bars)
    f_extend(nyam_lines, nyam_labels, nyam_boxes)

// NY Afternoon
if nypm_start and i_show_nypm
    f_clear(nypm_lines, nypm_labels, nypm_boxes)
    if not na(nypm_oline)
        line.delete(nypm_oline)
    nypm_oline := f_open_line(open, i_col_nypm)
    f_open_label(open, "NY Afternoon Open", i_col_nypm)
    f_draw_bands(nypm_lines, nypm_labels, nypm_boxes,
                 bar_index, open, "NYPM", i_col_nypm,
                 nypm_rng, nypm_mfe, nypm_mae,
                 nypm_bull_mfe, nypm_bull_mae,
                 nypm_bear_mfe, nypm_bear_mae)

if in_nypm and i_show_nypm
    if not na(nypm_oline)
        line.set_x2(nypm_oline, bar_index + i_proj_bars)
    f_extend(nypm_lines, nypm_labels, nypm_boxes)

// Custom
if cust_start and i_show_cust
    f_clear(cust_lines, cust_labels, cust_boxes)
    if not na(cust_oline)
        line.delete(cust_oline)
    cust_oline := f_open_line(open, i_col_cust)
    f_open_label(open, i_cust_label + " Open", i_col_cust)
    f_draw_bands(cust_lines, cust_labels, cust_boxes,
                 bar_index, open, i_cust_label, i_col_cust,
                 cust_rng, cust_mfe, cust_mae,
                 cust_bull_mfe, cust_bull_mae,
                 cust_bear_mfe, cust_bear_mae)

if in_cust and i_show_cust
    if not na(cust_oline)
        line.set_x2(cust_oline, bar_index + i_proj_bars)
    f_extend(cust_lines, cust_labels, cust_boxes)


// ═══════════════════════════════════════════════════════════════════
// SECTION 9 — OVERVIEW TABLE
// Always visible. One row per session. Shows range distribution
// (P25/P50/P75/P90) and bull/bear count for quick context.
// ═══════════════════════════════════════════════════════════════════

f_tbl1_row(tbl, row, name, rng_a, bull, bear, sess_col, sz) =>
    n   = array.size(rng_a)
    bg  = color.new(sess_col, 94)
    fnt = font.family_monospace
    c_tc  = color.rgb(50,  50,  50)
    c_dim = color.rgb(140, 140, 140)
    table.cell(tbl, 0, row, name,
         text_size=sz, text_color=sess_col, bgcolor=bg, text_font_family=fnt)
    table.cell(tbl, 1, row, str.tostring(array.size(rng_a)),
         text_size=sz, text_color=c_tc, bgcolor=bg, text_font_family=fnt)
    table.cell(tbl, 2, row, f_fmt_p(f_pct_val(rng_a, 25)),
         text_size=sz, text_color=c_tc, bgcolor=bg, text_font_family=fnt)
    table.cell(tbl, 3, row, f_fmt_p(f_pct_val(rng_a, 50)),
         text_size=sz, text_color=c_tc, bgcolor=bg, text_font_family=fnt)
    table.cell(tbl, 4, row, f_fmt_p(f_pct_val(rng_a, 75)),
         text_size=sz, text_color=c_tc, bgcolor=bg, text_font_family=fnt)
    table.cell(tbl, 5, row, f_fmt_p(f_pct_val(rng_a, 90)),
         text_size=sz, text_color=c_tc, bgcolor=bg, text_font_family=fnt)
    table.cell(tbl, 6, row,
         n >= 2 ? f_fmt_p(array.avg(rng_a)) : "—",
         text_size=sz, text_color=c_tc, bgcolor=bg, text_font_family=fnt)
    table.cell(tbl, 7, row,
         str.tostring(bull) + " / " + str.tostring(bear),
         text_size=sz, text_color=c_dim, bgcolor=bg, text_font_family=fnt)

if i_tbl1_show and barstate.islast

    var table tbl1 = table.new(f_tpos(i_tbl1_pos), 8, 7,
         bgcolor      = color.white,
         border_color = color.rgb(200, 200, 200),
         frame_color  = color.rgb(160, 160, 160),
         frame_width  = 1,
         border_width = 1)

    sz1      = f_tbl_size(i_tbl1_size)
    fnt      = font.family_monospace
    c_hdr_bg = color.rgb(30,  30,  30)
    c_hdr_tc = color.white
    c_dim    = color.rgb(140, 140, 140)
    c_ftr_bg = color.rgb(245, 245, 245)

    // Header row
    table.cell(tbl1, 0, 0, "Session",  text_size=sz1, text_color=c_hdr_tc, bgcolor=c_hdr_bg, text_font_family=fnt)
    table.cell(tbl1, 1, 0, "N",        text_size=sz1, text_color=c_hdr_tc, bgcolor=c_hdr_bg, text_font_family=fnt)
    table.cell(tbl1, 2, 0, "P25",      text_size=sz1, text_color=c_hdr_tc, bgcolor=c_hdr_bg, text_font_family=fnt)
    table.cell(tbl1, 3, 0, "P50",      text_size=sz1, text_color=c_hdr_tc, bgcolor=c_hdr_bg, text_font_family=fnt)
    table.cell(tbl1, 4, 0, "P75",      text_size=sz1, text_color=c_hdr_tc, bgcolor=c_hdr_bg, text_font_family=fnt)
    table.cell(tbl1, 5, 0, "P90",      text_size=sz1, text_color=c_hdr_tc, bgcolor=c_hdr_bg, text_font_family=fnt)
    table.cell(tbl1, 6, 0, "Mean",     text_size=sz1, text_color=c_hdr_tc, bgcolor=c_hdr_bg, text_font_family=fnt)
    table.cell(tbl1, 7, 0, "Bull/Bear",text_size=sz1, text_color=c_hdr_tc, bgcolor=c_hdr_bg, text_font_family=fnt)

    f_tbl1_row(tbl1, 1, "Asia",         asia_rng,  asia_bull_ct,  asia_bear_ct,  i_col_asia, sz1)
    f_tbl1_row(tbl1, 2, "London",       lon_rng,   lon_bull_ct,   lon_bear_ct,   i_col_lon,  sz1)
    f_tbl1_row(tbl1, 3, "NY Morning",   nyam_rng,  nyam_bull_ct,  nyam_bear_ct,  i_col_nyam, sz1)
    f_tbl1_row(tbl1, 4, "NY Afternoon", nypm_rng,  nypm_bull_ct,  nypm_bear_ct,  i_col_nypm, sz1)
    f_tbl1_row(tbl1, 5, i_cust_label,   cust_rng,  cust_bull_ct,  cust_bear_ct,  i_col_cust, sz1)

    // Footer
    table.cell(tbl1, 0, 6, "Lookback: 100 sessions",
         text_size=sz1, text_color=c_dim, bgcolor=c_ftr_bg, text_font_family=fnt)
    table.merge_cells(tbl1, 0, 6, 7, 6)

// ═══════════════════════════════════════════════════════════════════
// SECTION 10 — LIVE LEVEL TABLE
// Shows MFE/MAE reversion and next-level stats for the active
// session (or last closed session when no session is running).
// Columns: Level | Pts | Reached | Reverted | → Next
// ═══════════════════════════════════════════════════════════════════

// Track last closed session for display when market is between sessions
var string last_closed = ""
if asia_end
    last_closed := "ASIA"
if lon_end
    last_closed := "LON"
if nyam_end
    last_closed := "NYAM"
if nypm_end
    last_closed := "NYPM"
if cust_end
    last_closed := "CUST"

if i_tbl2_show and barstate.islast

    display_sess = curr_sess != "" ? curr_sess : last_closed
    is_live      = curr_sess != ""

    // Resolve metadata for display session
    string disp_name  = "—"
    float  disp_open  = na
    int    disp_n     = 0
    color  disp_col   = color.gray

    float mfe_p90_pts = na, float mfe_p75_pts = na
    float mfe_p50_pts = na, float mfe_p25_pts = na
    float mae_p90_pts = na, float mae_p75_pts = na
    float mae_p50_pts = na, float mae_p25_pts = na

    int mfe90_t = 0, int mfe90_opp = 0
    int mfe75_t = 0, int mfe75_nxt = 0, int mfe75_opp = 0
    int mfe50_t = 0, int mfe50_nxt = 0, int mfe50_opp = 0
    int mfe25_t = 0, int mfe25_nxt = 0, int mfe25_opp = 0
    int mae90_t = 0, int mae90_opp = 0
    int mae75_t = 0, int mae75_nxt = 0, int mae75_opp = 0
    int mae50_t = 0, int mae50_nxt = 0, int mae50_opp = 0
    int mae25_t = 0, int mae25_nxt = 0, int mae25_opp = 0

    if display_sess == "ASIA"
        disp_name    := "Asia  19:00–02:00 ET"
        disp_open    := asia_o
        disp_n       := array.size(asia_mfe)
        disp_col     := i_col_asia
        mfe_p90_pts  := f_pct_val(asia_mfe, 90)
        mfe_p75_pts  := f_pct_val(asia_mfe, 75)
        mfe_p50_pts  := f_pct_val(asia_mfe, 50)
        mfe_p25_pts  := f_pct_val(asia_mfe, 25)
        mae_p90_pts  := f_pct_val(asia_mae, 90)
        mae_p75_pts  := f_pct_val(asia_mae, 75)
        mae_p50_pts  := f_pct_val(asia_mae, 50)
        mae_p25_pts  := f_pct_val(asia_mae, 25)
        mfe90_t := asia_mfe90_tot, mfe90_opp := asia_mfe90_opp
        mfe75_t := asia_mfe75_tot, mfe75_nxt := asia_mfe75_nxt, mfe75_opp := asia_mfe75_opp
        mfe50_t := asia_mfe50_tot, mfe50_nxt := asia_mfe50_nxt, mfe50_opp := asia_mfe50_opp
        mfe25_t := asia_mfe25_tot, mfe25_nxt := asia_mfe25_nxt, mfe25_opp := asia_mfe25_opp
        mae90_t := asia_mae90_tot, mae90_opp := asia_mae90_opp
        mae75_t := asia_mae75_tot, mae75_nxt := asia_mae75_nxt, mae75_opp := asia_mae75_opp
        mae50_t := asia_mae50_tot, mae50_nxt := asia_mae50_nxt, mae50_opp := asia_mae50_opp
        mae25_t := asia_mae25_tot, mae25_nxt := asia_mae25_nxt, mae25_opp := asia_mae25_opp

    else if display_sess == "LON"
        disp_name    := "London  02:00–08:00 ET"
        disp_open    := lon_o
        disp_n       := array.size(lon_mfe)
        disp_col     := i_col_lon
        mfe_p90_pts  := f_pct_val(lon_mfe, 90)
        mfe_p75_pts  := f_pct_val(lon_mfe, 75)
        mfe_p50_pts  := f_pct_val(lon_mfe, 50)
        mfe_p25_pts  := f_pct_val(lon_mfe, 25)
        mae_p90_pts  := f_pct_val(lon_mae, 90)
        mae_p75_pts  := f_pct_val(lon_mae, 75)
        mae_p50_pts  := f_pct_val(lon_mae, 50)
        mae_p25_pts  := f_pct_val(lon_mae, 25)
        mfe90_t := lon_mfe90_tot, mfe90_opp := lon_mfe90_opp
        mfe75_t := lon_mfe75_tot, mfe75_nxt := lon_mfe75_nxt, mfe75_opp := lon_mfe75_opp
        mfe50_t := lon_mfe50_tot, mfe50_nxt := lon_mfe50_nxt, mfe50_opp := lon_mfe50_opp
        mfe25_t := lon_mfe25_tot, mfe25_nxt := lon_mfe25_nxt, mfe25_opp := lon_mfe25_opp
        mae90_t := lon_mae90_tot, mae90_opp := lon_mae90_opp
        mae75_t := lon_mae75_tot, mae75_nxt := lon_mae75_nxt, mae75_opp := lon_mae75_opp
        mae50_t := lon_mae50_tot, mae50_nxt := lon_mae50_nxt, mae50_opp := lon_mae50_opp
        mae25_t := lon_mae25_tot, mae25_nxt := lon_mae25_nxt, mae25_opp := lon_mae25_opp

    else if display_sess == "NYAM"
        disp_name    := "NY Morning  08:00–12:00 ET"
        disp_open    := nyam_o
        disp_n       := array.size(nyam_mfe)
        disp_col     := i_col_nyam
        mfe_p90_pts  := f_pct_val(nyam_mfe, 90)
        mfe_p75_pts  := f_pct_val(nyam_mfe, 75)
        mfe_p50_pts  := f_pct_val(nyam_mfe, 50)
        mfe_p25_pts  := f_pct_val(nyam_mfe, 25)
        mae_p90_pts  := f_pct_val(nyam_mae, 90)
        mae_p75_pts  := f_pct_val(nyam_mae, 75)
        mae_p50_pts  := f_pct_val(nyam_mae, 50)
        mae_p25_pts  := f_pct_val(nyam_mae, 25)
        mfe90_t := nyam_mfe90_tot, mfe90_opp := nyam_mfe90_opp
        mfe75_t := nyam_mfe75_tot, mfe75_nxt := nyam_mfe75_nxt, mfe75_opp := nyam_mfe75_opp
        mfe50_t := nyam_mfe50_tot, mfe50_nxt := nyam_mfe50_nxt, mfe50_opp := nyam_mfe50_opp
        mfe25_t := nyam_mfe25_tot, mfe25_nxt := nyam_mfe25_nxt, mfe25_opp := nyam_mfe25_opp
        mae90_t := nyam_mae90_tot, mae90_opp := nyam_mae90_opp
        mae75_t := nyam_mae75_tot, mae75_nxt := nyam_mae75_nxt, mae75_opp := nyam_mae75_opp
        mae50_t := nyam_mae50_tot, mae50_nxt := nyam_mae50_nxt, mae50_opp := nyam_mae50_opp
        mae25_t := nyam_mae25_tot, mae25_nxt := nyam_mae25_nxt, mae25_opp := nyam_mae25_opp

    else if display_sess == "NYPM"
        disp_name    := "NY Afternoon  12:00–17:00 ET"
        disp_open    := nypm_o
        disp_n       := array.size(nypm_mfe)
        disp_col     := i_col_nypm
        mfe_p90_pts  := f_pct_val(nypm_mfe, 90)
        mfe_p75_pts  := f_pct_val(nypm_mfe, 75)
        mfe_p50_pts  := f_pct_val(nypm_mfe, 50)
        mfe_p25_pts  := f_pct_val(nypm_mfe, 25)
        mae_p90_pts  := f_pct_val(nypm_mae, 90)
        mae_p75_pts  := f_pct_val(nypm_mae, 75)
        mae_p50_pts  := f_pct_val(nypm_mae, 50)
        mae_p25_pts  := f_pct_val(nypm_mae, 25)
        mfe90_t := nypm_mfe90_tot, mfe90_opp := nypm_mfe90_opp
        mfe75_t := nypm_mfe75_tot, mfe75_nxt := nypm_mfe75_nxt, mfe75_opp := nypm_mfe75_opp
        mfe50_t := nypm_mfe50_tot, mfe50_nxt := nypm_mfe50_nxt, mfe50_opp := nypm_mfe50_opp
        mfe25_t := nypm_mfe25_tot, mfe25_nxt := nypm_mfe25_nxt, mfe25_opp := nypm_mfe25_opp
        mae90_t := nypm_mae90_tot, mae90_opp := nypm_mae90_opp
        mae75_t := nypm_mae75_tot, mae75_nxt := nypm_mae75_nxt, mae75_opp := nypm_mae75_opp
        mae50_t := nypm_mae50_tot, mae50_nxt := nypm_mae50_nxt, mae50_opp := nypm_mae50_opp
        mae25_t := nypm_mae25_tot, mae25_nxt := nypm_mae25_nxt, mae25_opp := nypm_mae25_opp

    else if display_sess == "CUST"
        disp_name    := i_cust_label + "  " + i_cust_start + "–" + i_cust_end + " ET"
        disp_open    := cust_o
        disp_n       := array.size(cust_mfe)
        disp_col     := i_col_cust
        mfe_p90_pts  := f_pct_val(cust_mfe, 90)
        mfe_p75_pts  := f_pct_val(cust_mfe, 75)
        mfe_p50_pts  := f_pct_val(cust_mfe, 50)
        mfe_p25_pts  := f_pct_val(cust_mfe, 25)
        mae_p90_pts  := f_pct_val(cust_mae, 90)
        mae_p75_pts  := f_pct_val(cust_mae, 75)
        mae_p50_pts  := f_pct_val(cust_mae, 50)
        mae_p25_pts  := f_pct_val(cust_mae, 25)
        mfe90_t := cust_mfe90_tot, mfe90_opp := cust_mfe90_opp
        mfe75_t := cust_mfe75_tot, mfe75_nxt := cust_mfe75_nxt, mfe75_opp := cust_mfe75_opp
        mfe50_t := cust_mfe50_tot, mfe50_nxt := cust_mfe50_nxt, mfe50_opp := cust_mfe50_opp
        mfe25_t := cust_mfe25_tot, mfe25_nxt := cust_mfe25_nxt, mfe25_opp := cust_mfe25_opp
        mae90_t := cust_mae90_tot, mae90_opp := cust_mae90_opp
        mae75_t := cust_mae75_tot, mae75_nxt := cust_mae75_nxt, mae75_opp := cust_mae75_opp
        mae50_t := cust_mae50_tot, mae50_nxt := cust_mae50_nxt, mae50_opp := cust_mae50_opp
        mae25_t := cust_mae25_tot, mae25_nxt := cust_mae25_nxt, mae25_opp := cust_mae25_opp

    // Live price stats
    float dist_pts = is_live and not na(disp_open) ? close - disp_open : float(na)

    // Table setup — 5 cols, 12 rows
    var table tbl2 = table.new(f_tpos(i_tbl2_pos), 5, 12,
         bgcolor      = color.white,
         border_color = color.rgb(210, 210, 210),
         frame_color  = color.rgb(160, 160, 160),
         frame_width  = 1,
         border_width = 1)

    sz2      = f_tbl_size(i_tbl2_size)
    fnt      = font.family_monospace
    c_hdr_bg = color.new(disp_col, 20)
    c_hdr_tc = color.white
    c_col_bg = color.rgb(40,  40,  40)
    c_col_tc = color.white
    c_key_bg = color.rgb(245, 245, 245)
    c_key_tc = color.rgb(60,  60,  60)
    c_val_tc = color.rgb(30,  30,  30)
    c_mfe_bg = color.new(i_col_mfe, 92)
    c_mae_bg = color.new(i_col_mae, 92)
    c_ftr_bg = color.rgb(245, 245, 245)
    c_ftr_tc = color.rgb(160, 160, 160)

    dist_tc = not na(dist_pts) ?
         (dist_pts > 0 ? i_col_mfe : dist_pts < 0 ? i_col_mae : c_val_tc) : c_val_tc

    // Row 0 — session header
    table.cell(tbl2, 0, 0, disp_name,
         text_size=sz2, text_color=c_hdr_tc, bgcolor=c_hdr_bg,
         text_font_family=fnt, text_halign=text.align_left)
    table.merge_cells(tbl2, 0, 0, 3, 0)
    table.cell(tbl2, 4, 0, is_live ? "● LIVE" : "○ CLOSED",
         text_size=sz2, text_color=c_hdr_tc, bgcolor=c_hdr_bg,
         text_font_family=fnt, text_halign=text.align_right)

    // Row 1 — open + distance
    open_str = not na(disp_open) ? str.format("{0,number,#.##}", disp_open) : "—"
    table.cell(tbl2, 0, 1, "Open: " + open_str,
         text_size=sz2, text_color=c_key_tc, bgcolor=c_key_bg,
         text_font_family=fnt, text_halign=text.align_left)
    table.merge_cells(tbl2, 0, 1, 2, 1)
    table.cell(tbl2, 3, 1, is_live ? f_fmt_pts(dist_pts) : "—",
         text_size=sz2, text_color=dist_tc, bgcolor=c_key_bg,
         text_font_family=fnt, text_halign=text.align_right)
    table.merge_cells(tbl2, 3, 1, 4, 1)

    // Row 2 — column headers
    table.cell(tbl2, 0, 2, "Level",    text_size=sz2, text_color=c_col_tc, bgcolor=c_col_bg, text_font_family=fnt, text_halign=text.align_left)
    table.cell(tbl2, 1, 2, "Pts",       text_size=sz2, text_color=c_col_tc, bgcolor=c_col_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 2, 2, "Reached",   text_size=sz2, text_color=c_col_tc, bgcolor=c_col_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 3, 2, "→ Next",    text_size=sz2, text_color=c_col_tc, bgcolor=c_col_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 4, 2, "↓ Retrace",  text_size=sz2, text_color=c_col_tc, bgcolor=c_col_bg, text_font_family=fnt, text_halign=text.align_right)

    // ─── MFE rows ─────────────────────────────────────────────────
    // col 3 = → Next (continued to next level up)
    // col 4 = ↓ Reversal (hit P75 THEN reversed to MAE P25) — only P75 and P90
    table.cell(tbl2, 0, 3, "MFE P90 ▲", text_size=sz2, text_color=c_key_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_left)
    table.cell(tbl2, 1, 3, f_fmt_p(mfe_p90_pts), text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 2, 3, str.tostring(mfe90_t), text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 3, 3, "—", text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 4, 3, f_rev_str(mfe90_t, mfe90_opp), text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)

    table.cell(tbl2, 0, 4, "MFE P75 ▲", text_size=sz2, text_color=c_key_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_left)
    table.cell(tbl2, 1, 4, f_fmt_p(mfe_p75_pts), text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 2, 4, str.tostring(mfe75_t), text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 3, 4, f_rev_str(mfe75_t, mfe75_nxt), text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 4, 4, f_rev_str(mfe75_t, mfe75_opp), text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)

    table.cell(tbl2, 0, 5, "MFE P50 ▲", text_size=sz2, text_color=c_key_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_left)
    table.cell(tbl2, 1, 5, f_fmt_p(mfe_p50_pts), text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 2, 5, str.tostring(mfe50_t), text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 3, 5, f_rev_str(mfe50_t, mfe50_nxt), text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 4, 5, f_rev_str(mfe50_t, mfe50_opp), text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)

    table.cell(tbl2, 0, 6, "MFE P25 ▲", text_size=sz2, text_color=c_key_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_left)
    table.cell(tbl2, 1, 6, f_fmt_p(mfe_p25_pts), text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 2, 6, str.tostring(mfe25_t), text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 3, 6, f_rev_str(mfe25_t, mfe25_nxt), text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 4, 6, "—", text_size=sz2, text_color=c_val_tc, bgcolor=c_mfe_bg, text_font_family=fnt, text_halign=text.align_right)

    // ─── MAE rows ─────────────────────────────────────────────────
    table.cell(tbl2, 0, 7, "MAE P25 ▼", text_size=sz2, text_color=c_key_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_left)
    table.cell(tbl2, 1, 7, f_fmt_p(mae_p25_pts), text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 2, 7, str.tostring(mae25_t), text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 3, 7, f_rev_str(mae25_t, mae25_nxt), text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 4, 7, "—", text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)

    table.cell(tbl2, 0, 8, "MAE P50 ▼", text_size=sz2, text_color=c_key_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_left)
    table.cell(tbl2, 1, 8, f_fmt_p(mae_p50_pts), text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 2, 8, str.tostring(mae50_t), text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 3, 8, f_rev_str(mae50_t, mae50_nxt), text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 4, 8, f_rev_str(mae50_t, mae50_opp), text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)

    table.cell(tbl2, 0, 9, "MAE P75 ▼", text_size=sz2, text_color=c_key_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_left)
    table.cell(tbl2, 1, 9, f_fmt_p(mae_p75_pts), text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 2, 9, str.tostring(mae75_t), text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 3, 9, f_rev_str(mae75_t, mae75_nxt), text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 4, 9, f_rev_str(mae75_t, mae75_opp), text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)

    table.cell(tbl2, 0, 10, "MAE P90 ▼", text_size=sz2, text_color=c_key_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_left)
    table.cell(tbl2, 1, 10, f_fmt_p(mae_p90_pts), text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 2, 10, str.tostring(mae90_t), text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 3, 10, "—", text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)
    table.cell(tbl2, 4, 10, f_rev_str(mae90_t, mae90_opp), text_size=sz2, text_color=c_val_tc, bgcolor=c_mae_bg, text_font_family=fnt, text_halign=text.align_right)

    // Row 11 — footer
    table.cell(tbl2, 0, 11,
         str.tostring(disp_n) + " sessions  |  Lookback: 100",
         text_size=sz2, text_color=c_ftr_tc, bgcolor=c_ftr_bg,
         text_font_family=fnt, text_halign=text.align_left)
    table.merge_cells(tbl2, 0, 11, 4, 11)

Overview

Session Statistical Levels calculates and plots symmetric percentile range bands such as the median (P50), interquartile range (P25/P75), P10/P90, mean, and optional MFE/MAE excursion bands directly on the main chart. Settings allow customizing session hours, percentile displays, line styles, and color options to analyze intraday session volatility and structural price boundaries.

Details

Published by

TamaraKGreen on GitHub

Code credit

lucymatos, as written in the script's header

Type

Indicator, Pine Script v5

Draws

On the price chart

Category

Sessions & time, Support & resistance, Volatility & bands

Markets

Forex, Indices, Crypto

Timeframes

M1-M5, M15-H1

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Label SizestringTinyi_label_size
Asia (19:00–02:00 ET)booltruei_show_asia
Asia colourcolorcolor.rgb(255, 153, 0)i_col_asia
London (02:00–08:00 ET)booltruei_show_lon
London colourcolorcolor.rgb(41, 98, 255)i_col_lon
NY Morning (08:00–12:00 ET)booltruei_show_nyam
NY Morning colourcolorcolor.rgb(0, 150, 136)i_col_nyam
NY Afternoon (12:00–17:00 ET)booltruei_show_nypm
NY Afternoon colourcolorcolor.rgb(156, 39, 176)i_col_nypm
Custom Sessionboolfalsei_show_cust
Start (HHMM ET)string0900i_cust_start
End (HHMM ET)string1200i_cust_end
Show all 38 settings
SettingTypeDefaultVariable
LabelstringCustomi_cust_label
Custom colourcolorcolor.rgb(100, 100, 100)i_col_cust
Median (P50)booltruei_rng_p50
IQR (P25 / P75)booltruei_rng_iqr
P10 / P90booltruei_rng_p10p90
Meanbooltruei_rng_mean
Show Fillsbooltruei_rng_fills
Line StylestringDottedi_rng_style
Line Widthint1i_rng_width
P50 colourcolorcolor.rgb(20, 20, 20)i_col_p50
IQR colourcolorcolor.rgb(80, 80, 80)i_col_iqr
P10/P90 colourcolorcolor.rgb(130, 130, 130)i_col_p10p90
Mean colourcolorcolor.rgb(60, 60, 160)i_col_mean
Show MFE / MAE Bandsbooltruei_show_exc
Split Bull / Bear sessionsboolfalsei_bull_bear
Line StylestringSolidi_exc_style
Line Widthint1i_exc_width
MFE colourcolorcolor.rgb(30, 140, 30)i_col_mfe
MAE colourcolorcolor.rgb(180, 30, 30)i_col_mae
Show Overview Tablebooltruei_tbl1_show
PositionstringBottom Lefti_tbl1_pos
Text SizestringTinyi_tbl1_size
Show Live Level Tablebooltruei_tbl2_show
PositionstringBottom Righti_tbl2_pos
Text SizestringTinyi_tbl2_size
Label Offset (bars)int10i_proj_bars
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

56 stars

This indicator marks forex trading sessions and opening ranges on the price chart. It can draw Sydney, Tokyo, Frankfurt, London, and New York session boxes or five- and fifteen-minute opening ranges, plus an optional opening channel and a day-open range. Day r

Indicator v5 Sessions & timeSupport & resistance Repaints
Updated 2 months ago · None stated GitHub repository of Day Trading Booster by DGT

LoD Intraday Entry

by ChartsLector
41 stars

This overlay indicator marks the current day's low and a suggested entry zone a fraction of daily ATR below that low. It compares daily volume with a volume moving average, plots daily SMA and EMA distance, and draws an optional ATR-width price cloud. Labels c

Indicator v6 Support & resistanceVolatility & bands
Updated 2 days ago · None stated GitHub repository of LoD Intraday Entry

Zen Toolkit ETH

by Zen-Tim
29 stars

This indicator plots intraday reference levels, projection targets, and opening range boundaries tailored for continuous electronic trading session instruments such as gold. It calculates Average Bar Range targets in bullish and bearish multiples, previous day

Indicator v6 Support & resistanceSessions & time
Updated 2 weeks ago · MIT GitHub repository of Zen Toolkit ETH

This indicator combines six trading tools into a single chart overlay to optimize indicator limits. It calculates Bollinger Bands, projects weekend price boundaries, plots market structure elements like order blocks, breaker blocks, and MSB lines, marks New Yo

Indicator v6 Support & resistanceSMC / ICT / price action Repaints
6 stars

This indicator detects Turtle Soup liquidity sweeps and Candle Range Theory setups directly on the price chart. It checks breakout distances against ATR boundaries while requiring optional volume spikes and momentum shifts to confirm reversal signals or flag i

Indicator v5 SMC / ICT / price actionSupport & resistance

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers