// This Pine Script® code is licensed under Apache-2.0
// SPDX-License-Identifier: Apache-2.0
// © PineForge contributors 2026
//
// PF probe market-shift-probe-02-rolling-extreme — rolling highest/lowest tracking
// Clean-room: written from validation goal, not from source.
//
// Purpose: isolates the rolling-window extreme surface (`ta.highest(high, N)`
// and `ta.lowest(low, N)`) used by shift detectors to anchor their
// rebound/breakout reference levels. Entry triggers on `ta.crossover(close,
// ta.lowest(low, N)[1])` (close pierces the prior bar's rolling low →
// rebound long); short is symmetric on `ta.crossunder(close,
// ta.highest(high, N)[1])`. Using the [1]-shifted reference avoids the
// trivial "close == lowest" same-bar tautology and exercises history-access
// alignment in TV vs the engine.
//
// Validation goal: bit-exact trade list against TradingView's broker emulator
// on the reference 15-minute ETH-USDT-USDT feed. The window-length surface
// is the only meaningful drift candidate — `ta.highest`/`ta.lowest` warmup
// and series-history precision should agree perfectly through bar 50+.
//
// TV setup: 15m chart, ETH-USDT-USDT (Binance USDT-M Perpetual). Full window
// matching corpus/data/ohlcv_ETH-USDT-USDT_15m.csv. Strategy properties:
// leave defaults from script header. Export "List of trades" → tv_trades.csv.
//@version=6
strategy("PF probe market-shift-probe-02-rolling-extreme", shorttitle="PF_MS02_ROLL",
overlay=true, initial_capital=1000000,
commission_type=strategy.commission.percent, commission_value=0,
slippage=0, default_qty_type=strategy.fixed, default_qty_value=1,
pyramiding=1, process_orders_on_close=false)
// ---- inputs --------------------------------------------------------
int i_window = input.int(50, "Rolling window length", minval=10, maxval=200)
// ---- rolling extremes ---------------------------------------------
float roll_hi = ta.highest(high, i_window)
float roll_lo = ta.lowest(low, i_window)
// Reference the prior-bar value so the cross is not a self-tautology.
float ref_hi = roll_hi[1]
float ref_lo = roll_lo[1]
bool long_signal = ta.crossover(close, ref_lo)
bool short_signal = ta.crossunder(close, ref_hi)
// ---- routing -------------------------------------------------------
if long_signal and strategy.position_size <= 0
strategy.entry("L", strategy.long, qty=1, comment="rebound long")
if short_signal and strategy.position_size >= 0
strategy.entry("S", strategy.short, qty=1, comment="rebound short")