OPEN-SOURCE SCRIPT
Liquidity Retest Strategy (Apicode) - TP/SL Lines Fixed

Technical Documentation:
1. Purpose and underlying concept
This strategy targets a common behavior in liquid markets: liquidity sweeps around meaningful support/resistance levels, followed by a retest and rejection (reversal) with confirmation.
The core thesis is that many initial “breaks” are not continuation moves, but rather stop-runs and order harvesting. After the sweep, price reclaims the level and closes back on the opposite side, offering a structured entry with defined risk.
The strategy includes:
2. Main components
2.1. Volatility metric: ATR
atr = ta.atr(atrLength) is used in two essential places:
Optionally, ATR can also be used for:
2.2. Building S/R levels with pivots
Pivots are detected using:
Each confirmed pivot is stored in arrays:
The array size is capped by maxLevels, which reduces noise and manages chart resource usage (lines).
2.3. Selecting the “best” level each bar
On each bar, a single support S and/or resistance R candidate is chosen:
This produces dynamic “working levels” that adapt to price location and volatility.
2.4. Rejection pattern (retest + sweep)
After selecting the working level:
Support rejection (long setup)
Conditions:
This aims to capture a stop sweep below support followed by immediate recovery.
Resistance rejection (short setup)
Symmetric conditions:
High touches/crosses resistance: high >= R
Close rejects back below: close < R
Bearish candle: close < open
Sufficient wick above the level: (high - R) >= atr * minWickATR
2.5. Optional filters
Final signals are the rejection pattern AND enabled filters:
1.- Volume filter
2.- VWAP-like bias filter
A VWAP-like series is computed over vwapLength (typical price weighted by volume)
When useVWAPFilter = true:
- Longs only if close > vwap
- Shorts only if close < vwap
3.- EMA trend filter
Uptrend if EMA(fast) > EMA(slow)
When useTrendFilter = true:
- Longs only in uptrend
- Shorts only in downtrend
2.6. Backtest time window (time filter)
To keep testing focused and reduce long-history noise:
Entries are permitted only when time >= startTime.
3. Entry rules and position control
3.1. Entries
No pyramiding is allowed (pyramiding = 0). Position gating is handled by:
4. Risk management: TP/SL and trailing (with plotted lines)
4.1. Detecting entry/exit events
Events are identified via changes in strategy.position_size:
This drives per-trade line creation, updates, and cleanup of state variables.
4.2. Static TP/SL
On entry, entryPrice := strategy.position_avg_price is stored.
Percent mode (usePercent = true)
Long:
Short:
ATR mode (usePercent = false)
Long:
Short:
4.3. Trailing stop (custom)
While a position is open, the script tracks the most favorable excursion:
Long: hhSinceEntry = highest high since entry
Short: llSinceEntry = lowest low since entry
A trailing candidate is computed:
Percent trailing (useTrailPercent = true)
Long: trailCandidate = hhSinceEntry*(1 - trailPerc/100)
Short: trailCandidate = llSinceEntry*(1 + trailPerc/100)
ATR trailing (useTrailPercent = false)
Long: trailCandidate = hhSinceEntry - atr*trailATR
Short: trailCandidate = llSinceEntry + atr*trailATR
Then the effective stop is selected:
Long: slUsed = max(staticSL, trailCandidate) when useTrail is enabled
Short: slUsed = min(staticSL, trailCandidate) when useTrail is enabled
If useTrail is disabled, slUsed remains the static stop.
Take profit remains static:
tpUsed = staticTP
Exit orders are issued via:
strategy.exit(..., stop=slUsed, limit=tpUsed)
4.4. Per-trade TP/SL lines
On each entry, two lines are created (SL and TP) via f_createLines().
During the trade, the SL line updates when trailing moves the stop; TP remains fixed.
On exit (flatExit), both lines are finalized on the exit bar and left on the chart as historical references.
This makes it straightforward to visually audit each trade: entry context, intended TP, and trailing evolution until exit.
5. Visualization and debugging
BUY/SELL labels with configurable size (xsize)
Debug mode (showDebug) plots the chosen working support/resistance level each bar
Stored pivot levels are drawn using reusable line slots, projected a fixed 20 bars to the right to keep the chart readable and efficient
6. Parameter guidance and practical notes
pivotLookback / rightBars: controls pivot significance vs responsiveness. Lower rightBars confirms pivots earlier but can increase noise.
maxDistATR: too low may reject valid levels; too high may select distant, less relevant levels.
minWickATR: key quality gate for “real” sweeps. Higher values reduce frequency but often improve signal quality.
Filters:
Volume filter tends to help in ranges and active sessions.
VWAP bias is useful intraday to align trades with session positioning.
EMA trend filter is helpful in directional markets but may remove good mean-reversion setups.
Percent TP/SL: provides consistent behavior across assets with variable volatility, but is less adaptive to sudden regime shifts.
Percent trailing: can capture extensions well; calibrate trailPerc per asset/timeframe (too tight = premature exits).
7. Known limitations
Pivot-derived levels are a heuristic; in strong trends, valid retests may be limited.
The time filter uses timenow; behavior may vary depending on historical context and how the platform evaluates “current time.”
TP/SL and trailing are computed from bar OHLC; in live trading, intrabar sequencing and fills may differ from bar-close simulation.
1. Purpose and underlying concept
This strategy targets a common behavior in liquid markets: liquidity sweeps around meaningful support/resistance levels, followed by a retest and rejection (reversal) with confirmation.
The core thesis is that many initial “breaks” are not continuation moves, but rather stop-runs and order harvesting. After the sweep, price reclaims the level and closes back on the opposite side, offering a structured entry with defined risk.
The strategy includes:
- Support/Resistance detection via pivots
- Dynamic selection of the “working” level using an ATR-based proximity window
- Rejection validation via candle structure (wick + close)
- Optional filters: volume, VWAP-like bias, and EMA trend
- Risk management with static TP/SL (ATR-based or %), plus trailing stop (ATR-based or %), with per-trade lines plotted
2. Main components
2.1. Volatility metric: ATR
atr = ta.atr(atrLength) is used in two essential places:
- Level selection (proximity to S/R): prevents trading levels that are too far from current price.
- Sweep validation (minimum wick size): requires the wick to extend beyond the level by a volatility-relative amount.
Optionally, ATR can also be used for:
- Static TP/SL (when usePercent = false)
- Trailing stop (when useTrailPercent = false)
2.2. Building S/R levels with pivots
Pivots are detected using:
- pivotHigh = ta.pivothigh(pivotLookback, rightBars)
- pivotLow = ta.pivotlow(pivotLookback, rightBars)
Each confirmed pivot is stored in arrays:
- resistanceLevels for resistance
- supportLevels for support
The array size is capped by maxLevels, which reduces noise and manages chart resource usage (lines).
2.3. Selecting the “best” level each bar
On each bar, a single support S and/or resistance R candidate is chosen:
- Support: nearest level below price (L < price)
- Resistance: nearest level above price (L > price)
- Only levels within atr * maxDistATR are considered
This produces dynamic “working levels” that adapt to price location and volatility.
2.4. Rejection pattern (retest + sweep)
After selecting the working level:
Support rejection (long setup)
Conditions:
- Low touches/crosses support: low <= S
- Close reclaims above: close > S
- Bullish candle: close > open
- Sufficient wick below the level (liquidity sweep): (S - low) >= atr * minWickATR
This aims to capture a stop sweep below support followed by immediate recovery.
Resistance rejection (short setup)
Symmetric conditions:
High touches/crosses resistance: high >= R
Close rejects back below: close < R
Bearish candle: close < open
Sufficient wick above the level: (high - R) >= atr * minWickATR
2.5. Optional filters
Final signals are the rejection pattern AND enabled filters:
1.- Volume filter
- High volume is defined as: volume > SMA(volume, 20) * volMult
- When useVolFilter = true, setups require relatively elevated participation
2.- VWAP-like bias filter
A VWAP-like series is computed over vwapLength (typical price weighted by volume)
When useVWAPFilter = true:
- Longs only if close > vwap
- Shorts only if close < vwap
3.- EMA trend filter
Uptrend if EMA(fast) > EMA(slow)
When useTrendFilter = true:
- Longs only in uptrend
- Shorts only in downtrend
2.6. Backtest time window (time filter)
To keep testing focused and reduce long-history noise:
- useMaxLookbackDays enables the filter
- maxLookbackDays defines how many days back from timenow entries are allowed
Entries are permitted only when time >= startTime.
3. Entry rules and position control
3.1. Entries
- strategy.entry('Long', strategy.long) when longSetup and no long position is open
- strategy.entry('Short', strategy.short) when shortSetup and no short position is open
No pyramiding is allowed (pyramiding = 0). Position gating is handled by:
- Long allowed if strategy.position_size <= 0
- Short allowed if strategy.position_size >= 0
4. Risk management: TP/SL and trailing (with plotted lines)
4.1. Detecting entry/exit events
Events are identified via changes in strategy.position_size:
- LongEntry: transition into a long
- shortEntry: transition into a short
- flatExit: transition back to flat
This drives per-trade line creation, updates, and cleanup of state variables.
4.2. Static TP/SL
On entry, entryPrice := strategy.position_avg_price is stored.
Percent mode (usePercent = true)
Long:
- staticSL = entryPrice*(1 - slPerc/100)
- staticTP = entryPrice*(1 + tpPerc/100)
Short:
- staticSL = entryPrice*(1 + slPerc/100)
- staticTP = entryPrice*(1 - tpPerc/100)
ATR mode (usePercent = false)
Long:
- staticSL = entryPrice - atrAtEntry*slATR
- staticTP = entryPrice + atrAtEntry*tpATR
Short:
- staticSL = entryPrice + atrAtEntry*slATR
- staticTP = entryPrice - atrAtEntry*tpATR
4.3. Trailing stop (custom)
While a position is open, the script tracks the most favorable excursion:
Long: hhSinceEntry = highest high since entry
Short: llSinceEntry = lowest low since entry
A trailing candidate is computed:
Percent trailing (useTrailPercent = true)
Long: trailCandidate = hhSinceEntry*(1 - trailPerc/100)
Short: trailCandidate = llSinceEntry*(1 + trailPerc/100)
ATR trailing (useTrailPercent = false)
Long: trailCandidate = hhSinceEntry - atr*trailATR
Short: trailCandidate = llSinceEntry + atr*trailATR
Then the effective stop is selected:
Long: slUsed = max(staticSL, trailCandidate) when useTrail is enabled
Short: slUsed = min(staticSL, trailCandidate) when useTrail is enabled
If useTrail is disabled, slUsed remains the static stop.
Take profit remains static:
tpUsed = staticTP
Exit orders are issued via:
strategy.exit(..., stop=slUsed, limit=tpUsed)
4.4. Per-trade TP/SL lines
On each entry, two lines are created (SL and TP) via f_createLines().
During the trade, the SL line updates when trailing moves the stop; TP remains fixed.
On exit (flatExit), both lines are finalized on the exit bar and left on the chart as historical references.
This makes it straightforward to visually audit each trade: entry context, intended TP, and trailing evolution until exit.
5. Visualization and debugging
BUY/SELL labels with configurable size (xsize)
Debug mode (showDebug) plots the chosen working support/resistance level each bar
Stored pivot levels are drawn using reusable line slots, projected a fixed 20 bars to the right to keep the chart readable and efficient
6. Parameter guidance and practical notes
pivotLookback / rightBars: controls pivot significance vs responsiveness. Lower rightBars confirms pivots earlier but can increase noise.
maxDistATR: too low may reject valid levels; too high may select distant, less relevant levels.
minWickATR: key quality gate for “real” sweeps. Higher values reduce frequency but often improve signal quality.
Filters:
Volume filter tends to help in ranges and active sessions.
VWAP bias is useful intraday to align trades with session positioning.
EMA trend filter is helpful in directional markets but may remove good mean-reversion setups.
Percent TP/SL: provides consistent behavior across assets with variable volatility, but is less adaptive to sudden regime shifts.
Percent trailing: can capture extensions well; calibrate trailPerc per asset/timeframe (too tight = premature exits).
7. Known limitations
Pivot-derived levels are a heuristic; in strong trends, valid retests may be limited.
The time filter uses timenow; behavior may vary depending on historical context and how the platform evaluates “current time.”
TP/SL and trailing are computed from bar OHLC; in live trading, intrabar sequencing and fills may differ from bar-close simulation.
Skrypt open-source
W zgodzie z duchem TradingView twórca tego skryptu udostępnił go jako open-source, aby użytkownicy mogli przejrzeć i zweryfikować jego działanie. Ukłony dla autora. Korzystanie jest bezpłatne, jednak ponowna publikacja kodu podlega naszym Zasadom serwisu.
Wyłączenie odpowiedzialności
Informacje i publikacje nie stanowią i nie powinny być traktowane jako porady finansowe, inwestycyjne, tradingowe ani jakiekolwiek inne rekomendacje dostarczane lub zatwierdzone przez TradingView. Więcej informacji znajduje się w Warunkach użytkowania.
Skrypt open-source
W zgodzie z duchem TradingView twórca tego skryptu udostępnił go jako open-source, aby użytkownicy mogli przejrzeć i zweryfikować jego działanie. Ukłony dla autora. Korzystanie jest bezpłatne, jednak ponowna publikacja kodu podlega naszym Zasadom serwisu.
Wyłączenie odpowiedzialności
Informacje i publikacje nie stanowią i nie powinny być traktowane jako porady finansowe, inwestycyjne, tradingowe ani jakiekolwiek inne rekomendacje dostarczane lub zatwierdzone przez TradingView. Więcej informacji znajduje się w Warunkach użytkowania.