Strategy vault / Trend following
Adaptive Price Channel Strategy
This strategy is an adaptive price channel strategy based on the Average True Range (ATR) indicator and Average Directional Index (ADX). It aims to identify sideways markets and trends in price movements and make…

Overview
This strategy is an adaptive price channel strategy based on the Average True Range (ATR) indicator and Average Directional Index (ADX). It aims to identify sideways markets and trends in price movements and make trades accordingly.
Strategy Logic
Calculate the highest high (HH) and lowest low (LL) over a given length. Also calculate ATR over the same length.
Calculate +DI and -DI based on upward and downward price moves. Then calculate ADX.
If ADX < 25, the market is considered sideways. If close > upper channel (HH - ATR multiplier * ATR), go long. If close < lower channel (LL + ATR multiplier * ATR), go short.
If ADX >= 25 and +DI > -DI, market is bullish. If close > upper channel, go long.
If ADX >= 25 and +DI < -DI, market is bearish. If close < lower channel, go short.
Exit position after exit_length bars since entry.
Advantage Analysis
The strategy adapts automatically based on market conditions, using channel strategy in sideways market and trend following in trending market.
Using ATR and ADX ensures adaptiveness. ATR adjusts channel width, ADX determines trend.
Forced exit adds stability.
Risk Analysis
ADX can generate false signals frequently.
Poor ATR and ADX parameters lead to bad performance.
Unable to effectively guard against black swan events.
Optimization Directions
Optimize parameters for ATR and ADX to improve adaptability.
Add stop loss to limit losses.
Add filters to avoid false signals.
Conclusion
The strategy combines indicators and mechanisms to adapt across market conditions. But misjudgements can happen due to indicator limitations. Future optimizations on parameters and risk control.
Parameters
| Name | Default | What it controls |
|---|---|---|
| v_input_1 | 20 | Length |
| v_input_2 | 10 | Exit After X Periods |
| v_input_3 | 3.2 | ATR Multiplier |
| v_input_4 | timestamp(2019-01-15T08:15:15+00:00) | Start Date |
| v_input_5 | timestamp(2033-04-01T08:15:00+00:00) | End Date |
Source Pine Script
/*backtest
start: 2023-11-03 00:00:00
end: 2023-12-03 00:00:00
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/
//@version=5
strategy("Adaptive Price Channel Strategy", overlay=true)
length = input(20, title="Length")
exit_length = input(10, title="Exit After X Periods")
atr_multiplier = input(3.2, title="ATR Multiplier")
startDate = input(defval = timestamp("2019-01-15T08:15:15+00:00"), title = "Start Date")
endDate = input(defval = timestamp("2033-04-01T08:15:00+00:00"), title = "End Date")
hh = ta.highest(high, length)
ll = ta.lowest(low, length)
atr = ta.atr(length)
// calculate +DI and -DI
upMove = high - high[1]
downMove = low[1] - low
plusDM = na(upMove[1]) ? na : (upMove > downMove and upMove > 0 ? upMove : 0)
minusDM = na(downMove[1]) ? na : (downMove > upMove and downMove > 0 ? downMove : 0)
plusDI = ta.rma(plusDM, length) / atr * 100
minusDI = ta.rma(minusDM, length) / atr * 100
// calculate ADX
dx = math.abs(plusDI - minusDI) / (plusDI + minusDI) * 100
adx = ta.rma(dx, length)
var int barSinceEntry = na
if (not na(close[length]) )
if (adx < 25) // Sideways market
if (close > hh - atr_multiplier * atr)
strategy.entry("PChLE", strategy.long, comment="PChLE")
barSinceEntry := 0
else if (close < ll + atr_multiplier * atr)
strategy.entry("PChSE", strategy.short, comment="PChSE")
barSinceEntry := 0
else if (adx >= 25 and plusDI > minusDI) // Bullish market
if (close > hh - atr_multiplier * atr)
strategy.entry("PChLE", strategy.long, comment="PChLE")
barSinceEntry := 0
else if (adx >= 25 and plusDI < minusDI) // Bearish market
if (close < ll + atr_multiplier * atr)
strategy.entry("PChSE", strategy.short, comment="PChSE")
barSinceEntry := 0
if (na(barSinceEntry))
barSinceEntry := barSinceEntry[1] + 1
else if (barSinceEntry >= exit_length)
strategy.close("PChLE")
strategy.close("PChSE")
barSinceEntry := na
plot(hh, title="Highest High", color=color.green, linewidth=2)
plot(ll, title="Lowest Low", color=color.red, linewidth=2)
Published by ChaoZhang on the FMZ strategy square · last modified 2023-12-04. Collected in the Quant Trading Vault. Unvalidated research: re-test with your own data and costs before trusting it.
Build this with AgenKit
A spec is not a trading system. Paste this into your coding agent and AgenKit runs a specialist team — architecture, test-first build, risk gates, review — with paper trading on by default.
/agenkit build a production-grade trading bot with a backtest engine, risk controls and paper trading by default from strategies/Adaptive-Price-Channel-Strategy.md- npx agenkit install engineering-kit in your project
- Paste the command into your agent and approve each phase
- Get tests, backtest, risk controls and a paper-trading switch
Understand it first
Before you run this, read the lesson behind the idea and how to backtest it honestly. Specs like this one are the survivors of an unknown number of trials; deflate their results accordingly.
Related specs
- Adaptive Risk Management Strategy Based on Dynamic ATR and Moving Average CrossoverPine Script · Trend following · 2h
- Dual EMA Filtered ATR Adaptive Trend Following StrategyPine Script · Trend following · 1h
- Dual Moving Average Trend Detection with Volatility Based Stop Loss StrategyPine Script · Trend following · 1d
- Dynamic EMA Trend Detection with ATR Threshold StrategyPine Script · Trend following · 1h
- Dynamic Multi Indicator Trend Recognition Strategy with Triple Sync AnalysisPine Script · Trend following · 1d
- Extreme version of Noros Trend Moving Averages StrategyPine Script · Trend following · 1h