
The KDJ Extreme Reversal Trend Following Strategy is a quantitative trading system that combines momentum reversal and trend following concepts. The core of this strategy lies in capturing the first reversal signal after the J indicator reaches extreme values (0 or 100), while using the EMA676 line for trend direction filtering to ensure that the trading direction aligns with the main trend. The system employs precise entry conditions, flexible position management, and strict risk control mechanisms to find high-probability trading opportunities in volatile markets. The strategy is particularly suitable for tracking rebounds after technical indicators show overbought or oversold conditions, by monitoring the pattern of J value changes over 3 consecutive candles to confirm potential trend turning points, thereby establishing positions at the early stages of price reversals to capture significant price movements.
The core logic of this strategy is built on the characteristics of the J value in the KDJ indicator, combined with trend filtering for precise entry. The specific principles are as follows:
J Value Extreme Identification: The strategy monitors whether the J value reaches the preset extreme range (default upper limit 100, lower limit 0), which typically represents market conditions of excessive buying or selling.
Continuous Change Pattern Confirmation: The strategy requires that after the J value reaches an extreme, there must be a unidirectional change over 3 consecutive candles (continuous rise or continuous fall), which confirms the strong movement of the indicator.
Reversal Signal Capture: After the J value completes a unidirectional movement over 3 consecutive candles, the strategy detects the first opposite direction change, i.e., the turning point where the J value shifts from a continuous rise to a fall, or from a continuous fall to a rise.
Trend Direction Filtering: The strategy uses the EMA676 line as a trend judgment standard, only considering long signals when the price is above the line, and short signals when the price is below the line, ensuring that the trading direction is consistent with the overall trend.
Dynamic Take-Profit and Stop-Loss: The strategy calculates take-profit and stop-loss levels based on a percentage of the entry price, with default settings of 3% for take-profit and 2.2% for stop-loss, achieving a risk-reward ratio greater than 1.
Intelligent Position Management: The system provides two position calculation methods - fixed contract quantity and risk percentage-based. The latter dynamically adjusts position size based on the risk exposure of each trade, optimizing the efficiency of capital utilization.
After in-depth analysis of the code, this strategy demonstrates the following significant advantages:
Precise Signal Triggering Mechanism: By requiring the J value not only to reach extremes but also to undergo unidirectional movement over 3 consecutive candles before capturing the first reversal, this compound condition greatly improves the reliability of the signals and reduces false breakouts.
Perfect Combination of Trend and Reversal: The strategy cleverly integrates trend following (EMA676 direction filtering) and reversal trading (J value extreme rebound), both respecting the major trend direction and capturing high-probability rebound opportunities within the trend.
Adaptive Risk Management: The code implements dynamic position calculation based on risk percentage, keeping the risk exposure of each trade consistent regardless of market volatility changes, maintaining stable risk control.
Clear Visual Feedback: The strategy plots entry signals, take-profit and stop-loss trigger points, and key price lines on the chart, allowing traders to intuitively understand the execution logic and results of each trade.
Flexible Parameter Configuration: The system provides a rich set of adjustable parameters, including KDJ calculation periods, EMA length, extreme value settings, take-profit and stop-loss ratios, allowing the strategy to adapt to different market environments and trading instruments.
Early Warning Mechanism: The code designs early warning conditions for approaching signal triggers, such as when the J value approaches the extreme zone or is about to form an entry signal, which can notify traders in advance to prepare, improving operational efficiency.
Despite the sophisticated design of this strategy, there are still the following potential risks:
Stop-Loss Failure in Extreme Market Conditions: During market gaps or extreme volatility, the preset percentage stop-loss may not execute at the expected price, resulting in actual losses exceeding expectations. The solution is to introduce off-market stop-loss mechanisms or consider using on-market conditional orders as a backup.
Moving Average Lag Risk: As a long-period moving average, EMA676 has significant lag, which may provide incorrect directional guidance during the initial stages of trend reversals. It is recommended to combine multi-period analysis or add short-term trend confirmation indicators to optimize signal quality.
Parameter Optimization Overfitting: Current parameters (such as KDJ period 60, extreme settings 100⁄0) may be derived from historical data optimization, posing a risk of overfitting. It is recommended to verify parameter robustness through forward testing and testing across different periods.
J Value Calculation Deviation: The strategy uses a custom bcwsma function to calculate KDJ values, which may differ from standard KDJ calculations on different platforms, leading to inconsistencies between backtesting and live trading signals. Consistency in calculation methods should be confirmed before live trading.
Low Liquidity Market Risk: In markets with lower trading volume, the slippage for take-profit and stop-loss may be larger, affecting the actual performance of the strategy. It is recommended to apply this strategy in high-liquidity markets or mainstream trading instruments.
Unstable Signal Frequency: Signals based on extreme reversals may vary significantly in frequency across different market environments, leading to unstable capital utilization efficiency. Consider adding auxiliary trading signals or multi-timeframe confirmation mechanisms to smooth trading frequency.
Based on the current characteristics of the strategy, the following optimization directions can be considered:
Dynamic Extreme Value Settings: The current strategy uses fixed extreme upper and lower limits (100 and 0). Consider dynamically adjusting the extreme range based on historical volatility to adapt to different volatility environments, such as narrowing the extreme range during low volatility periods and expanding it during high volatility periods.
Multi-Timeframe Confirmation: Introduce higher timeframe signal confirmation, for example, requiring the J value on the daily timeframe to also be in the extreme zone, or confirming consistency between 3-minute and 15-minute timeframe signals to improve signal quality.
Intelligent Take-Profit Mechanism: Implement dynamic take-profit strategies, such as partial position closing or ATR (Average True Range) based take-profit level calculation, or using trailing stops after profits reach a certain level to maximize trend profit capture.
Market Environment Filtering: Add volatility filtering conditions to pause trading or adjust position sizes in excessively volatile or extremely low volatility market environments, avoiding trading in market environments that are not suitable for the strategy’s characteristics.
Signal Strength Grading: Based on factors such as J value reversal amplitude, candlestick patterns, and volume confirmation, grade signal strength and dynamically adjust position size according to signal strength, increasing positions for strong signals and decreasing for weak ones.
Machine Learning Optimization: Introduce machine learning algorithms to automatically optimize parameter combinations, or extract features from historical signals to build prediction models to evaluate the success probability of each signal, improving the adaptability and robustness of the strategy.
The KDJ Extreme Reversal Trend Following Strategy is a well-structured, logically clear quantitative trading system that captures technical indicator extreme reversals combined with trend direction filtering, maintaining a high win rate while controlling risk. The core advantages of the strategy lie in the precision of its signal triggering mechanism and the completeness of its risk management, making it suitable for market environments with clear medium to long-term trends but with volatility.
From an implementation perspective, the strategy code has a clear structure, rigorous calculation logic, and includes complete trading management functions, with detailed implementation from signal generation, position calculation to take-profit and stop-loss execution. Through the optimization directions proposed in this article, especially dynamic parameter adjustment and multi-dimensional signal confirmation, the stability and adaptability of the strategy can be further enhanced.
For traders, when applying this strategy, attention should be paid to verifying the applicability of parameters under different market conditions and adjusting take-profit, stop-loss, and position settings according to personal risk preferences. At the same time, it is recommended to combine fundamental analysis and technical analysis from higher timeframes to improve the comprehensiveness and accuracy of trading decisions.
//@version=6
strategy("J值极值趋势跟随策略", overlay = true,
default_qty_type = strategy.percent_of_equity, default_qty_value = 10, // 降低每笔交易的仓位大小
initial_capital = 10000,
margin_long = 20, margin_short = 20) // 设置合理的保证金要求
// === 策略说明:J值极值趋势跟随策略 ===
// 主图:显示J值连续下降后反弹的买点和连续上升后回调的卖点
// 副图:显示J线走势、中轴线、极值区域
// 方向过滤:676均线,价格在上方只做多,下方只做空
// 止盈止损:基于百分比波动,默认1%止盈1%止损
// === 输入参数 ===
lengthK = input.int(60, title = "K period")
lengthD = input.int(3, title = "D period")
smoothK = input.int(3, title = "Smooth K")
emaLength = input.int(576, title = "趋势EMA周期", inline="ema")
extremeHigh = input.float(100, title = "J值极值上限", minval = 80, maxval = 120)
extremeLow = input.float(0, title = "J值极值下限", minval = -20, maxval = 20)
// === 止盈止损参数(改为百分比) ===
takeProfitPercent = input.float(3, title = "止盈百分比", minval = 0.1, step = 0.1)
stopLossPercent = input.float(2.2, title = "止损百分比", minval = 0.1, step = 0.1)
// === 风险控制参数 ===
useFixedPositionSize = input.bool(true, title = "使用固定合约数量")
fixedPositionSize = input.float(1.0, title = "固定合约数量", minval = 0.1, step = 0.1)
riskPerTrade = input.float(1.0, title = "每笔交易风险百分比", minval = 0.1, maxval = 10, step = 0.1)
// === KDJ计算(使用与bitcoinwisdom一致的算法) ===
// 自定义加权移动平均函数(与bitcoinwisdom一致)
bcwsma(s, l, m) =>
var _bcwsma = 0.0
_bcwsma := (m*s + (l-m)*nz(_bcwsma[1])) / l
_bcwsma
highestHigh = ta.highest(high, lengthK)
lowestLow = ta.lowest(low, lengthK)
rsv = (close - lowestLow) / (highestHigh - lowestLow) * 100
K = bcwsma(rsv, smoothK, 1)
D = bcwsma(K, lengthD, 1)
J = 3 * K - 2 * D
// === 676均线方向判断 ===
ema676 = ta.ema(close, emaLength)
trendUp = close > ema676 // 价格在676均线上方
trendDown = close < ema676 // 价格在676均线下方
// === 检测J值连续下降和上升 ===
// 检测连续3根下降:J < J[1] < J[2] < J[3]
jContinuousDown = J < J[1] and J[1] < J[2] and J[2] < J[3]
// 检测连续3根上升:J > J[1] > J[2] > J[3]
jContinuousUp = J > J[1] and J[1] > J[2] and J[2] > J[3]
// === 检测反弹和回调(必须在极值区域内) ===
// 反弹:当前J值上升,且之前连续下降,且J值在极值下限以下
jBounce = J > J[1] and jContinuousDown[1] and J[1] <= extremeLow
// 回调:当前J值下降,且之前连续上升,且J值在极值上限以上
jPullback = J < J[1] and jContinuousUp[1] and J[1] >= extremeHigh
// === 开仓信号(带方向过滤) ===
// 买点:J值连续下降后反弹 + 价格在676均线上方
longEntry = jBounce and trendUp
// 卖点:J值连续上升后回调 + 价格在676均线下方
shortEntry = jPullback and trendDown
// === 记录开仓价格和止盈止损价格 ===
var float entryPrice = na
var float tpPrice = na
var float slPrice = na
// === 计算仓位大小 ===
// 基于风险百分比的仓位计算需要考虑止损百分比
positionSize = useFixedPositionSize ? fixedPositionSize : (strategy.equity * (riskPerTrade / 100)) / (close * stopLossPercent / 100)
// === 止盈止损信号变量 ===
var bool longTakeProfitHit = false
var bool longStopLossHit = false
var bool shortTakeProfitHit = false
var bool shortStopLossHit = false
// === 警报信号指示器 ===
// 多单入场信号将触发
longSignalComing = J <= extremeLow and jContinuousDown and trendUp
// 空单入场信号将触发
shortSignalComing = J >= extremeHigh and jContinuousUp and trendDown
// J值接近极值区域
jNearExtremeLow = J <= extremeLow + 5 and J > extremeLow
jNearExtremeHigh = J >= extremeHigh - 5 and J < extremeHigh
// === 策略执行 ===
if (longEntry and strategy.position_size == 0)
entryPrice := close
// 计算基于百分比的止盈止损价格
tpPrice := entryPrice * (1 + takeProfitPercent / 100)
slPrice := entryPrice * (1 - stopLossPercent / 100)
strategy.entry("多单", strategy.long, qty=positionSize)
// 重置止盈止损信号
longTakeProfitHit := false
longStopLossHit := false
if (shortEntry and strategy.position_size == 0)
entryPrice := close
// 计算基于百分比的止盈止损价格
tpPrice := entryPrice * (1 - takeProfitPercent / 100)
slPrice := entryPrice * (1 + stopLossPercent / 100)
strategy.entry("空单", strategy.short, qty=positionSize)
// 重置止盈止损信号
shortTakeProfitHit := false
shortStopLossHit := false
// === 手动检查止盈止损条件 ===
// 多单止盈止损
longTPHit = strategy.position_size > 0 and high >= tpPrice and not longTakeProfitHit
longSLHit = strategy.position_size > 0 and low <= slPrice and not longStopLossHit
if (longTPHit)
strategy.close("多单", comment="止盈")
longTakeProfitHit := true
if (longSLHit)
strategy.close("多单", comment="止损")
longStopLossHit := true
// 空单止盈止损
shortTPHit = strategy.position_size < 0 and low <= tpPrice and not shortTakeProfitHit
shortSLHit = strategy.position_size < 0 and high >= slPrice and not shortStopLossHit
if (shortTPHit)
strategy.close("空单", comment="止盈")
shortTakeProfitHit := true
if (shortSLHit)
strategy.close("空单", comment="止损")
shortStopLossHit := true
// === 在主图绘制676均线 ===
plot(ema676, title="676 EMA", color=color.blue, linewidth=2)
// === 在主图标注开仓信号 ===
plotshape(longEntry, title="多单入场", location=location.belowbar, color=color.lime, style=shape.triangleup, size=size.small, text="多单", force_overlay=true)
plotshape(shortEntry, title="空单入场", location=location.abovebar, color=color.red, style=shape.triangledown, size=size.small, text="空单", force_overlay=true)
// === 添加止盈止损信号 ===
// 多单止盈信号
plotshape(longTPHit, title="多单止盈", location=location.abovebar,
color=color.green, style=shape.circle, size=size.normal, text="止盈", force_overlay=true)
// 多单止损信号
plotshape(longSLHit, title="多单止损", location=location.abovebar,
color=color.red, style=shape.xcross, size=size.normal, text="止损", force_overlay=true)
// 空单止盈信号
plotshape(shortTPHit, title="空单止盈", location=location.belowbar,
color=color.green, style=shape.circle, size=size.normal, text="止盈", force_overlay=true)
// 空单止损信号
plotshape(shortSLHit, title="空单止损", location=location.belowbar,
color=color.red, style=shape.xcross, size=size.normal, text="止损", force_overlay=true)
// === 绘制止盈止损线 ===
plot(strategy.position_size != 0 ? tpPrice : na, title="止盈", color=color.green, style=plot.style_line, linewidth=1)
plot(strategy.position_size != 0 ? slPrice : na, title="止损", color=color.red, style=plot.style_line, linewidth=1)
plot(strategy.position_size != 0 ? entryPrice : na, title="入场价", color=color.yellow, style=plot.style_line, linewidth=1)
// === 设置警报条件(使用常量字符串) ===
// 基础信号警报
alertcondition(longEntry, title="多单入场信号", message="J值极值策略: 多单入场信号触发")
alertcondition(shortEntry, title="空单入场信号", message="J值极值策略: 空单入场信号触发")
alertcondition(longTPHit, title="多单止盈触发", message="J值极值策略: 多单止盈触发")
alertcondition(longSLHit, title="多单止损触发", message="J值极值策略: 多单止损触发")
alertcondition(shortTPHit, title="空单止盈触发", message="J值极值策略: 空单止盈触发")
alertcondition(shortSLHit, title="空单止损触发", message="J值极值策略: 空单止损触发")
// === 添加交易详情标签 ===
if (longTPHit)
label.new(bar_index, high, text="多单止盈 +" + str.tostring(takeProfitPercent) + "%",
style=label.style_label_down, color=color.green, textcolor=color.white)
if (longSLHit)
label.new(bar_index, low, text="多单止损 -" + str.tostring(stopLossPercent) + "%",
style=label.style_label_up, color=color.red, textcolor=color.white)
if (shortTPHit)
label.new(bar_index, low, text="空单止盈 +" + str.tostring(takeProfitPercent) + "%",
style=label.style_label_up, color=color.green, textcolor=color.white)
if (shortSLHit)
label.new(bar_index, high, text="空单止损 -" + str.tostring(stopLossPercent) + "%",
style=label.style_label_down, color=color.red, textcolor=color.white)