추세 사다리 평균화 전략: 시장이 횡보할 때 우아하게 "평평하게 눕는" 방법은?

ADX EMA ATR DI
생성 날짜: 2025-10-09 14:28:37 마지막으로 수정됨: 2025-10-09 14:28:37
복사: 0 클릭수: 268
avatar of ianzeng123 ianzeng123
2
집중하다
319
수행원

추세 사다리 평균화 전략: 시장이 횡보할 때 우아하게 “평평하게 눕는” 방법은? 추세 사다리 평균화 전략: 시장이 횡보할 때 우아하게 “평평하게 눕는” 방법은?

왜 전통적인 트렌드 트래킹 전략이 격동의 시내에서 자주 “돌아”가는 걸까요?

양자 거래 전문가로서 저는 종종 이런 질문을 받습니다. 왜 동향시장에서 잘하는 전략들이 동향시장에서 급격히 물러나게 되는 걸까요?

답은 간단합니다. 대부분의 트렌드 추적 전략은 “트렌드 강박증”으로 고통 받고 있습니다. 그들은 항상 시장 환경 속에서도 높은 주파수를 유지하려고 노력하지만 기본적인 사실을 무시합니다.시장의 70%는 수평 변동 상태입니다.

오늘 우리가 분석하고자 하는 ‘트렌드 사다리 평균 전략’은 바로 이 문제점을 해결하기 위한 흥미로운 해결책을 제시합니다.트렌드 시장에서 적극적으로 따라가며, 흔들리는 시장에서 ‘아래로 깔끔하게’

“단계 평균”이란 무엇인가요? 그리고 어떻게 트렌드 추적을 재정의할 수 있을까요?

전통적인 이동 평균 전략에는 치명적인 결함이 있습니다. 그들은 항상 변화합니다. 시장이 강세를 보거나 수평으로 흔들리더라도, 평균선은 가격 변동에 따라 계속 조정됩니다. 이것은 많은 가짜 신호를 초래합니다.

“단계 평균”의 핵심은 다음과 같습니다.평행선이 특정 조건에서 ‘냉동’하도록 하는 것

구체적인 구현 논리는 다음과 같습니다:

  1. 트렌드 상태 탐지시장의 강도를 판단하는 ADX 지표

    • ADX>25: 강세를 보이는 시장
    • 평균 경사율 <0.3%: 가로수지 시장
  2. 동적 평선 전환

    • 강한 트렌드: 정상 추적 EMA 21
    • 가로면: 평선 “냉동”은 수평 위치에서, 지원 / 저항을 형성

이 디자인의 기발한 점은 다음과 같습니다.이것은 전략이 다른 시장 환경에 따라 다른 “인격”을 나타낼 수 있게 해줍니다.은 추세에 민감하고, 흔들림에 안정적이다.

트렌드 캡처 시스템을 어떻게 구현할 수 있을까요?

기본 계단 평균 메커니즘 외에도, 이 전략에는 “트렌드 캡처” 모듈이 포함되어 있습니다.

빠른 회전 메커니즘

  • 그리고 그 후로, 이 모든 것들이 다시 시작되었습니다.
  • 3주기에 걸쳐 새로운 포지션을 빠르게 구축
  • 조건: ADX > 30 그리고 DI+와 DI-의 차이는 > 10

이 디자인은 전통적인 전략의 중요한 문제점을 해결합니다.트렌드 반전 초기에 포지션을 빠르게 조정하는 방법

이 시나리오를 상상해보세요: 당신은 막 상쇄로 인해 다수 상위 포지션을 청산했고, 그 결과 시장은 즉시 강렬한 하향 추세를 나타냅니다. 전통적인 전략은 새로운 신호 확인을 기다려야 할 수도 있지만, 이 “트렌드 캡처” 시스템은 3 주기에 걸쳐 상위 포지션을 빠르게 구축할 수 있습니다.

리스크 관리: 왜 시장 상태를 구분해야 하는가?

이 전략의 가장 중요한 교훈은차별화된 위험 관리 장치

수평 시장에서의 위험 관리

  • 스톱 손실은 계단 평행선 근처로 조정됩니다.
  • ATR 배수를 낮추고, 손해배상을 강화합니다.
  • 목표비트 설정이 더 보수적입니다.

트렌드 시장에서의 위험 관리

  • 표준 ATR 배수를 사용해서 손해를 막는다.
  • 계단형 이동 상쇄를 활성화
  • 더 큰 가격 변동이 허용됩니다.

이 디자인은 중요한 거래 철학을 나타냅니다.다른 시장 환경은 다른 위험 선호를 요구합니다.ᄒ 横盘 시장에서는 더 조심해야 하고, 트렌드 시장에서는 더 많은 여유를 줘야 합니다 ᄒ

계단형 이동 상쇄: 수익보호와 트렌드 추적의 균형을 어떻게 잡을 수 있을까요?

전통적인 이동식 상쇄는 지나치게 기계화되어 있기 때문에, 너무 긴축해서 조기 퇴출을 하게 되거나, 너무 느긋해서 수익을 효과적으로 보호할 수 없다. 이 전략의 계단형 이동식 상쇄는 더 똑똑한 해결책을 제시한다:

계단 설정 논리

  • ATR의 동적 계산에 기초한 계단 간격
  • 최대 5개의 계단 레벨을 설정합니다.
  • 한 계단을 돌파할 때마다, Stop Loss이 증가합니다.

이 디자인의 장점은 다음과 같습니다:이윤을 보호하면서도 트렌드에 충분한 여유를 줄 수 있습니다.

실제 적용에서 주의해야 할 사항은 무엇인가?

내 실무 경험에 따르면, 이런 전략은 다음과 같은 점들을 고려해야 합니다.

  1. 매개 변수 최적화 함수ADX 지점을 지나치게 최적화하지 마십시오. 25-30 사이의 값은 대부분의 시장에서 안정적입니다.

  2. 시장 적응성이 전략은 극도로 변동적인 환경에서 ATR 배수를 조정해야 할 수 있는 변동성이 적당한 시장에 적합합니다.

  3. 자금 관리단일 포지션은 전체 자본의 10%를 초과하지 않는 것이 좋습니다. 특히 트렌드 캡처 기능이 활성화되면

  4. 함정 회귀특히 불안정한 시장에서 자주 거래되는 경우 슬라이드 포인트와 수수료의 영향에 주의를 기울여야 합니다.

이 전략의 혁신적인 가치는 무엇인가?

이 전략은 수량화 전략의 발전의 관점에서 볼 때 중요한 진화의 방향을 나타냅니다.단일 논리에서 다중 상태 적응으로의 전환

전통적인 전략은 모든 시장 상황에 대해 일정한 논리를 사용하려고 노력하지만, 이 전략은 ‘지구적 적합성’의 지혜를 보여줍니다.

  • 트렌드 마켓에서 급진적인 트렌드 추적자처럼 행동합니다.
  • 은 시장에서 보수적 인 간격 거래자처럼 행동합니다.

이 디자인 아이디어는 전략 개발자들에게 중요한 교훈이 될 수 있습니다.우리는 전략이 고정된 논리를 맹목적으로 수행하는 것이 아니라 “시장 인식” 능력을 갖춰야 합니다.

마지막으로, 모든 전략이 다재다능하지 않다는 것을 강조해야 합니다. 이 계단 평균 전략은 이론적으로 우아하지만 실제 적용에서는 특정 시장 환경과 개인 위험 선호도에 따라 조정해야합니다.가장 좋은 전략은 항상 당신에게 가장 적합한 전략입니다.

전략 소스 코드
/*backtest
start: 2024-10-09 00:00:00
end: 2025-10-07 08:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Futures_Binance","currency":"SOL_USDT","balance":500000}]
*/

//@version=5
strategy("Trend Following Ladder Average Strategy", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=10)

// ═══════════════════════════════════════════════════════════════════════════════
// SETTINGS AND PARAMETERS
// ═══════════════════════════════════════════════════════════════════════════════

// Ladder Average Settings
ma_length = input.int(title="Average Period", defval=21, minval=5)
ma_type = input.string(title="Average Type", defval="EMA", options=["SMA", "EMA", "WMA"])

// Trend Strength Settings
adx_length = input.int(title="Trend Strength Period (ADX)", defval=14, minval=5)
trend_threshold = input.float(title="Trend Strength Threshold", defval=25.0, minval=10.0, step=5.0)
sideways_slope_threshold = input.float(title="Sideways Market Slope Threshold", defval=0.3, minval=0.1, step=0.1)

// Trend Catching Settings
enable_trend_catch = input.bool(title="Trend Catching System", defval=true)
trend_catch_adx_threshold = input.float(title="Trend Catch ADX Threshold", defval=30.0, minval=20.0, step=5.0)
trend_catch_di_diff = input.float(title="DI+ DI- Difference Threshold", defval=10.0, minval=5.0, step=2.5)
quick_entry_bars = input.int(title="Quick Entry Waiting Bars", defval=3, minval=1, maxval=10)

// ATR and Volatility Settings
atr_length = input.int(title="ATR Period", defval=14, minval=1)
atr_multiplier = input.float(title="ATR Multiplier", defval=2.0, minval=0.1, step=0.1)

// Ladder Trailing Stop Settings
ladder_step = input.float(title="Ladder Step Size (%)", defval=1.0, minval=0.1, step=0.1)
max_ladders = input.int(title="Maximum Ladder Count", defval=5, minval=2, maxval=10)

// Stop Loss and Take Profit Settings
use_stop_loss = input.bool(title="Use Stop Loss", defval=false)
use_take_profit = input.bool(title="Use Take Profit", defval=false)
use_trailing_stop = input.bool(title="Use Trailing Stop", defval=true)

sl_type = input.string(title="Stop Loss Type", defval="ATR", options=["ATR", "Percent", "Points"])
sl_atr_multiplier = input.float(title="SL ATR Multiplier", defval=2.0, minval=0.5, step=0.1)
sl_percent = input.float(title="SL Percent (%)", defval=2.0, minval=0.1, step=0.1)
sl_points = input.float(title="SL Points", defval=100, minval=1)

tp_type = input.string(title="Take Profit Type", defval="ATR", options=["ATR", "Percent", "Points", "Risk/Reward"])
tp_atr_multiplier = input.float(title="TP ATR Multiplier", defval=3.0, minval=0.5, step=0.1)
tp_percent = input.float(title="TP Percent (%)", defval=3.0, minval=0.1, step=0.1)
tp_points = input.float(title="TP Points", defval=150, minval=1)
tp_risk_reward = input.float(title="Risk/Reward Ratio", defval=2.0, minval=0.5, step=0.1)

// Horizontal Level Settings
horizontal_lookback = input.int(title="Horizontal Level Stabilization Period", defval=10, minval=3)

// ═══════════════════════════════════════════════════════════════════════════════
// INDICATORS AND CALCULATIONS
// ═══════════════════════════════════════════════════════════════════════════════

// ATR calculation
atr_value = ta.atr(atr_length)

// Moving Average calculation
ma_value = ma_type == "SMA" ? ta.sma(close, ma_length) : ma_type == "EMA" ? ta.ema(close, ma_length) : ma_type == "WMA" ? ta.wma(close, ma_length) : ta.ema(close, ma_length)

// ADX (Trend Strength) calculation - Manual calculation
tr = math.max(high - low, math.max(math.abs(high - close[1]), math.abs(low - close[1])))
plus_dm = high - high[1] > low[1] - low ? math.max(high - high[1], 0) : 0
minus_dm = low[1] - low > high - high[1] ? math.max(low[1] - low, 0) : 0
plus_di = 100 * ta.rma(plus_dm, adx_length) / ta.rma(tr, adx_length)
minus_di = 100 * ta.rma(minus_dm, adx_length) / ta.rma(tr, adx_length)
adx_value = 100 * ta.rma(math.abs(plus_di - minus_di) / (plus_di + minus_di), adx_length)

// MA slope calculation (for sideways market detection)
ma_slope = (ma_value - ma_value[5]) / ma_value[5] * 100

// Trend state detection
is_strong_trend = adx_value > trend_threshold
is_sideways_by_slope = math.abs(ma_slope) < sideways_slope_threshold
is_sideways = not is_strong_trend or is_sideways_by_slope

// Trend direction detection (DI+ vs DI-)
is_uptrend = plus_di > minus_di
is_downtrend = minus_di > plus_di
di_difference = math.abs(plus_di - minus_di)

// Strong trend momentum detection
strong_uptrend = adx_value > trend_catch_adx_threshold and plus_di > minus_di and di_difference > trend_catch_di_diff
strong_downtrend = adx_value > trend_catch_adx_threshold and minus_di > plus_di and di_difference > trend_catch_di_diff

// Position tracking system
var bool just_closed_long = false
var bool just_closed_short = false
var int bars_since_close = 0

// Position closure tracking - Fixed
if strategy.position_size == 0 and strategy.position_size[1] != 0
    if strategy.position_size[1] > 0
        just_closed_long := true
        just_closed_short := false
    else
        just_closed_short := true  
        just_closed_long := false
    bars_since_close := 0
else if strategy.position_size == 0
    bars_since_close += 1
    if bars_since_close > quick_entry_bars
        just_closed_long := false
        just_closed_short := false
else
    just_closed_long := false
    just_closed_short := false
    bars_since_close := 0

// Ladder Average System
var float ladder_ma = na
var float horizontal_level = na
var int sideways_count = 0

// Trend-following ladder average
if is_strong_trend and not is_sideways_by_slope
    // Normal MA tracking in strong trend
    ladder_ma := ma_value
    sideways_count := 0
else
    // When trend weakens or in sideways market
    sideways_count += 1
    if sideways_count >= horizontal_lookback or na(horizontal_level)
        horizontal_level := ma_value
    ladder_ma := horizontal_level

// Market state
market_state = is_strong_trend and not is_sideways_by_slope ? "TREND" : "SIDEWAYS"

// Volatility measurement
volatility = atr_value / close * 100

// ═══════════════════════════════════════════════════════════════════════════════
// STOP LOSS AND TAKE PROFIT CALCULATIONS
// ═══════════════════════════════════════════════════════════════════════════════

// Stop Loss calculation function
calculate_stop_loss(entry_price_val, is_long) =>
    sl_value = sl_type == "ATR" ? (is_long ? entry_price_val - (atr_value * sl_atr_multiplier) : entry_price_val + (atr_value * sl_atr_multiplier)) : sl_type == "Percent" ? (is_long ? entry_price_val * (1 - sl_percent / 100) : entry_price_val * (1 + sl_percent / 100)) : sl_type == "Points" ? (is_long ? entry_price_val - sl_points : entry_price_val + sl_points) : (is_long ? entry_price_val - (atr_value * sl_atr_multiplier) : entry_price_val + (atr_value * sl_atr_multiplier))
    sl_adjusted = if is_sideways
        is_long ? math.min(sl_value, ladder_ma - atr_value * 0.5) : math.max(sl_value, ladder_ma + atr_value * 0.5)
    else
        sl_value
    sl_adjusted

// Take Profit calculation function
calculate_take_profit(entry_price_val, stop_loss_val, is_long) =>
    tp_value = tp_type == "ATR" ? (is_long ? entry_price_val + (atr_value * tp_atr_multiplier) : entry_price_val - (atr_value * tp_atr_multiplier)) : tp_type == "Percent" ? (is_long ? entry_price_val * (1 + tp_percent / 100) : entry_price_val * (1 - tp_percent / 100)) : tp_type == "Points" ? (is_long ? entry_price_val + tp_points : entry_price_val - tp_points) : tp_type == "Risk/Reward" ? (is_long ? entry_price_val + (math.abs(entry_price_val - stop_loss_val) * tp_risk_reward) : entry_price_val - (math.abs(entry_price_val - stop_loss_val) * tp_risk_reward)) : (is_long ? entry_price_val + (atr_value * tp_atr_multiplier) : entry_price_val - (atr_value * tp_atr_multiplier))
    tp_adjusted = if is_sideways
        is_long ? math.max(tp_value, ladder_ma + atr_value * 1.5) : math.min(tp_value, ladder_ma - atr_value * 1.5)
    else
        tp_value
    tp_adjusted

var float current_sl = na
var float current_tp = na

// ═══════════════════════════════════════════════════════════════════════════════
// ENTRY SIGNALS
// ═══════════════════════════════════════════════════════════════════════════════

// Normal entry conditions
normal_long = strategy.position_size == 0 and ((is_strong_trend and close > ladder_ma and close[1] <= ladder_ma[1]) or (is_sideways and close < ladder_ma and close > ladder_ma - atr_value))
normal_short = strategy.position_size == 0 and ((is_strong_trend and close < ladder_ma and close[1] >= ladder_ma[1]) or (is_sideways and close > ladder_ma and close < ladder_ma + atr_value))

// Trend catching entry conditions
trend_catch_long = enable_trend_catch and strategy.position_size == 0 and just_closed_short and bars_since_close <= quick_entry_bars and strong_uptrend and close > close[1] and close > ladder_ma
trend_catch_short = enable_trend_catch and strategy.position_size == 0 and just_closed_long and bars_since_close <= quick_entry_bars and strong_downtrend and close < close[1] and close < ladder_ma

// Strong momentum entry conditions (even if no position closed, but strong trend exists)
momentum_long = enable_trend_catch and strategy.position_size == 0 and strong_uptrend and close > ladder_ma and close > close[1] and close > open
momentum_short = enable_trend_catch and strategy.position_size == 0 and strong_downtrend and close < ladder_ma and close < close[1] and close < open

// Combined entry conditions
long_condition = normal_long or trend_catch_long or momentum_long
short_condition = normal_short or trend_catch_short or momentum_short

// Entry type determination
entry_type = if trend_catch_long or trend_catch_short
    "TREND_CATCH"
else if momentum_long or momentum_short
    "MOMENTUM"
else
    market_state

// ═══════════════════════════════════════════════════════════════════════════════
// LADDER TRAILING STOP SYSTEM
// ═══════════════════════════════════════════════════════════════════════════════

var float[] ladder_levels = array.new<float>()
var float current_trailing_stop = na
var float entry_price = na

// Calculate ladder levels function
calculate_ladder_levels(entry_price_val, is_long) =>
    ladder_array = array.new<float>()
    base_level = ladder_ma
    for i = 1 to max_ladders
        level_value = if is_long
            base_level + (atr_value * atr_multiplier * i * ladder_step / 100)
        else
            base_level - (atr_value * atr_multiplier * i * ladder_step / 100)
        array.push(ladder_array, level_value)
    ladder_array

// Trailing stop update function
update_trailing_stop(entry_price_val, current_price, is_long) =>
    stop_level = if is_long
        initial_stop = is_sideways ? ladder_ma - atr_value : entry_price_val - (atr_value * atr_multiplier)
        new_stop = initial_stop
        if array.size(ladder_levels) > 0
            for i = 0 to array.size(ladder_levels) - 1
                level_value = array.get(ladder_levels, i)
                if current_price >= level_value
                    adjusted_stop = is_sideways ? ladder_ma : entry_price_val + (atr_value * atr_multiplier * (i + 1) * 0.3)
                    if adjusted_stop > new_stop
                        new_stop := adjusted_stop
        new_stop
    else
        initial_stop = is_sideways ? ladder_ma + atr_value : entry_price_val + (atr_value * atr_multiplier)
        new_stop = initial_stop
        if array.size(ladder_levels) > 0
            for i = 0 to array.size(ladder_levels) - 1
                level_value = array.get(ladder_levels, i)
                if current_price <= level_value
                    adjusted_stop = is_sideways ? ladder_ma : entry_price_val - (atr_value * atr_multiplier * (i + 1) * 0.3)
                    if adjusted_stop < new_stop
                        new_stop := adjusted_stop
        new_stop
    stop_level

// ═══════════════════════════════════════════════════════════════════════════════
// POSITION MANAGEMENT
// ═══════════════════════════════════════════════════════════════════════════════

// Long position entry
if long_condition
    strategy.entry("Long", strategy.long, comment="Long: " + market_state)
    entry_price := close
    ladder_levels := calculate_ladder_levels(close, true)
    
    // Stop Loss calculation (only if active)
    if use_stop_loss
        current_sl := calculate_stop_loss(close, true)
    
    // Take Profit calculation (only if active)
    if use_take_profit
        temp_sl = use_stop_loss ? current_sl : close - (atr_value * sl_atr_multiplier)
        current_tp := calculate_take_profit(close, temp_sl, true)
    
    // Trailing stop initialization (only if active)
    if use_trailing_stop
        current_trailing_stop := is_sideways ? ladder_ma - atr_value : close - (atr_value * atr_multiplier)

// Short position entry
if short_condition
    strategy.entry("Short", strategy.short, comment="Short: " + market_state)
    entry_price := close
    ladder_levels := calculate_ladder_levels(close, false)
    
    // Stop Loss calculation (only if active)
    if use_stop_loss
        current_sl := calculate_stop_loss(close, false)
    
    // Take Profit calculation (only if active)
    if use_take_profit
        temp_sl = use_stop_loss ? current_sl : close + (atr_value * sl_atr_multiplier)
        current_tp := calculate_take_profit(close, temp_sl, false)
    
    // Trailing stop initialization (only if active)
    if use_trailing_stop
        current_trailing_stop := is_sideways ? ladder_ma + atr_value : close + (atr_value * atr_multiplier)

// Position exit management
if strategy.position_size > 0  // Long position
    // If using fixed SL/TP
    if use_stop_loss and use_take_profit
        strategy.exit("Long Exit", "Long", stop=current_sl, limit=current_tp, comment="SL/TP")
    else if use_stop_loss and not use_take_profit
        strategy.exit("Long Exit", "Long", stop=current_sl, comment="SL Only")
    else if not use_stop_loss and use_take_profit
        strategy.exit("Long Exit", "Long", limit=current_tp, comment="TP Only")
    
    // If using trailing stop (optional)
    if use_trailing_stop
        current_trailing_stop := update_trailing_stop(entry_price, close, true)
        if close <= current_trailing_stop
            strategy.close("Long", comment="Trailing Stop")

if strategy.position_size < 0  // Short position
    // If using fixed SL/TP
    if use_stop_loss and use_take_profit
        strategy.exit("Short Exit", "Short", stop=current_sl, limit=current_tp, comment="SL/TP")
    else if use_stop_loss and not use_take_profit
        strategy.exit("Short Exit", "Short", stop=current_sl, comment="SL Only")
    else if not use_stop_loss and use_take_profit
        strategy.exit("Short Exit", "Short", limit=current_tp, comment="TP Only")
    
    // If using trailing stop (optional)
    if use_trailing_stop
        current_trailing_stop := update_trailing_stop(entry_price, close, false)
        if close >= current_trailing_stop
            strategy.close("Short", comment="Trailing Stop")



// ═══════════════════════════════════════════════════════════════════════════════
// VISUALIZATION
// ═══════════════════════════════════════════════════════════════════════════════

// Ladder Average plot
plot(ladder_ma, color=is_sideways ? color.orange : (ma_slope > 0 ? color.green : color.red), linewidth=3, title="Ladder Average")

// Horizontal level plot
plot(is_sideways ? horizontal_level : na, color=color.yellow, style=plot.style_circles, linewidth=2, title="Horizontal Level")

// ATR-based bands
upper_band = ladder_ma + atr_value
lower_band = ladder_ma - atr_value
plot(upper_band, color=color.new(color.blue, 70), title="Upper ATR Band")
plot(lower_band, color=color.new(color.blue, 70), title="Lower ATR Band")

// Stop Loss and Take Profit plots (only if active)
plot(strategy.position_size != 0 and use_stop_loss ? current_sl : na, color=color.red, style=plot.style_circles, linewidth=2, title="Stop Loss")
plot(strategy.position_size != 0 and use_take_profit ? current_tp : na, color=color.green, style=plot.style_circles, linewidth=2, title="Take Profit")

// Trailing stop plot (only if active)
plot(strategy.position_size > 0 and use_trailing_stop ? current_trailing_stop : na, color=color.orange, style=plot.style_stepline, linewidth=2, title="Long Trailing Stop")
plot(strategy.position_size < 0 and use_trailing_stop ? current_trailing_stop : na, color=color.orange, style=plot.style_stepline, linewidth=2, title="Short Trailing Stop")

// Market state background color
bgcolor(is_sideways ? color.new(color.yellow, 95) : (is_strong_trend ? color.new(color.green, 98) : color.new(color.gray, 98)), title="Market State")