다차원 트렌드 필터

ADX DI CCI RSI ATR VOLUME
생성 날짜: 2025-09-08 13:49:10 마지막으로 수정됨: 2025-09-08 13:49:10
복사: 0 클릭수: 255
avatar of ianzeng123 ianzeng123
2
집중하다
319
수행원

다차원 트렌드 필터 다차원 트렌드 필터

6중 필터링 메커니즘은 일반적인 기술 지표 조합이 아닙니다.

수천 개의 전략을 보았는데, 대부분은 하나의 지표의 간단한 조합이었다. 이 전략은 ADX, DI, CCI, RSI, ATR, 트랜스매트 6차원의 필터링 조건을 직접 통합했다. 장난을 치기 위해서가 아니라, 하나의 지표의 가짜 신호 문제를 해결하기 위해서였다. 재검토 데이터는 여러 번의 필터링 후 신호 품질이 눈에 띄게 향상되었으나, 신호 주파수가 약 40% 감소한 것으로 나타났습니다.

ADX+DI 조합: 트렌드 강도와 방향의 이중 검증

전통적인 전략은 트렌드 강도나 트렌드 방향을 보고, ADX와 DI를 체계적으로 결합하는 사람은 거의 없다. 여기서 디자인은 똑똑하다: DI+/DI- 교차는 방향을 결정하고, ADX값은 [[:default_25) 약한 트렌드를 필터링한다. 실험적으로 ADX가 25시 이하의 거래 신호의 성공률은 45%에 불과하고, 25시 이상의 거래 신호의 성공률은 62%까지 상승한다. 따라서 ADX 필터는 선택 사항이 아니라 필수품이다.

CCI와 이동 평균의 동적 결합

CCI 길이는 20주기이며, 14주기 이동 평균과 함께 작동한다. 이 파라미터 조합은 최적화되어 민감도와 안정성 사이에서 균형을 잡을 수 있다. 5가지 이동 평균 유형을 지원하지만, 실제 전투에서 SMA와 EMA 효과가 가장 안정적이다. 핵심은 정밀 교차 또는 간단한 높고 낮은 비교를 선택할 수 있다는 데 있다. 정밀 교차 신호는 적지만 품질은 더 높다.

RSI 경계 필터링: 과매매 함정을 피하라

RSI 필터는 3070 경계로 설정되어 있는데, 이는 기각을 피하기 위한 것이 아니라, 극단적인 상황에서의 가짜 돌파구를 피하기 위한 것이다. RSI가 30보다 낮을 때만 더 많은 것을 할 수 있고, 70보다 높을 때만 공백을 할 수 있다. 이 디자인은 전략이 많은 위기 시장의 가짜 신호를 피하는데 도움을 준다.

ATR와 거래량: 시장의 활발함에 대한 두 가지 보험

ATR 필터링은 시장의 충분한 변동성을 보장하며, 기본 값은 1.0이다. 거래량 필터링은 현재 거래량이 20주기를 초과하는 평균의 1.5배가 필요합니다. 이 두 조건은 결합하여 많은 저품질 거래 기회를 필터링합니다. 데이터는 두 조건을 충족시키는 신호가 평균 지분 수익률이 충족되지 않은 것보다 35% 높다는 것을 보여줍니다.

세 가지 출전 메커니즘: 다양한 시장 환경에 대한 유연성

이동 평균 출장, ADX 변화 상쇄, 성과 상쇄 3가지의 메커니즘은 독립적으로 또는 조합으로 사용할 수 있다. 이동 평균 출장은 트렌드 시장에 적합하며, ADX 변화 상쇄는 트렌드 전환에 적합하며, 성과 상쇄는 마지막 보험이다. 실전 조언: 트렌드가 분명할 때 MA로 출장, 흔들리는 시장에 ADX 변화 상쇄, 극단적 인 경우 성과 상쇄를 활성화하십시오.

역거래 기능: 손실에서 기회를 찾아라

Countertrade 기능은 평점 후에 즉시 역전 포지션을 열 수 있다. 이것은 도박이 아니라 기술 지표의 역전에 기반한 논리이다. 그러나, 이 기능은 강한 트렌드 시장에서 연속적인 손실을 초래할 수 있으므로, 흔들림 시장이나 트렌드 말기에만 사용하는 것이 좋습니다.

위험 경고와 적용 시나리오

이 전략은 트렌드가 명확한 시장에서 우수한 성능을 발휘하지만, 수평 변동이 있을 때 신호는 희귀하다. 여러 번의 필터링은 신호 품질을 향상시키지만, 놓친 기회의 위험을 증가시킵니다. 역사적인 회귀는 미래의 수익을 나타내지 않으며, 실물 거래는 엄격한 자금 관리가 필요합니다. 초기 포지션은 전체 자본의 50%를 초과하지 않으며, 시장 환경에 따라 변수를 조정하는 것이 좋습니다.

전략 소스 코드
/*backtest
start: 2024-09-08 00:00:00
end: 2025-09-06 08:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDC"}]
*/

//@version=6
strategy("Optimized ADX DI CCI Strategy", shorttitle="ADXCCI Opt")

// Input Groups
group_indicators = "Indicator Settings"
indicator_timeframe = input.timeframe("", "Indicator Timeframe", options=["", "1", "5", "15", "30", "60", "240", "D", "W"], group=group_indicators, tooltip="Empty uses chart timeframe")

group_adx = "ADX & DI Settings"
adx_di_len = input.int(30, "DI Length", minval=1, group=group_adx)
adx_smooth_len = input.int(14, "ADX Smoothing Length", minval=1, group=group_adx)
use_adx_filter = input.bool(false, "Use ADX Filter", group=group_adx)
adx_threshold = input.int(25, "ADX Threshold", minval=0, group=group_adx)

group_cci = "CCI Settings"
cci_length = input.int(20, "CCI Length", minval=1, group=group_cci)
cci_src = input.source(hlc3, "CCI Source", group=group_cci)
ma_type = input.string("SMA", "CCI MA Type", options=["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group=group_cci)
ma_length = input.int(14, "CCI MA Length", minval=1, group=group_cci)

group_rsi = "RSI Filter Settings"
use_rsi_filter = input.bool(false, "Use RSI Filter", group=group_rsi)
rsi_length = input.int(14, "RSI Length", minval=1, group=group_rsi)
rsi_lower_limit = input.int(30, "RSI Lower Limit", minval=0, maxval=100, group=group_rsi)
rsi_upper_limit = input.int(70, "RSI Upper Limit", minval=0, maxval=100, group=group_rsi)

group_atr = "ATR Filter Settings"
use_atr_filter = input.bool(false, "Use ATR Filter", group=group_atr, tooltip="If enabled, requires ATR to exceed threshold for signals")
atr_length = input.int(14, "ATR Length", minval=1, group=group_atr)
atr_threshold = input.float(1.0, "ATR Threshold", minval=0.0, step=0.1, group=group_atr, tooltip="Minimum ATR value for valid signals")

group_volume = "Volume Filter Settings"
use_volume_filter = input.bool(false, "Use Volume Filter", group=group_volume, tooltip="If enabled, requires volume to exceed threshold for signals")
volume_length = input.int(20, "Volume MA Length", minval=1, group=group_volume, tooltip="Period for volume moving average")
volume_threshold_multiplier = input.float(1.5, "Volume Threshold Multiplier", minval=0.1, step=0.1, group=group_volume, tooltip="Volume must exceed MA by this factor")

group_signal = "Signal Settings"
cross_window = input.int(0, "Cross Window (Bars)", minval=0, maxval=5, group=group_signal, tooltip="0 means exact same bar, higher allows recent crosses")
allow_long = input.bool(true, "Allow Long Trades", group=group_signal, tooltip="Only allows new Long trades, closing open trades still possible")
allow_short = input.bool(true, "Allow Short Trades", group=group_signal, tooltip="Only allows new Short trades, closing open trades still possible")
buy_di_cross = input.bool(true, "Require DI+/DI- Cross for Buy", group=group_signal, tooltip="If unchecked, DI+ > DI- is enough")
buy_cci_cross = input.bool(true, "Require CCI Cross for Buy", group=group_signal, tooltip="If unchecked, CCI > MA is enough")
sell_di_cross = input.bool(true, "Require DI+/DI- Cross for Sell", group=group_signal, tooltip="If unchecked, DI+ < DI- is enough")
sell_cci_cross = input.bool(true, "Require CCI Cross for Sell", group=group_signal, tooltip="If unchecked, CCI < MA is enough")
countertrade = input.bool(true, "Countertrade", group=group_signal, tooltip="If checked, open opposite trade after closing one")
color_background = input.bool(true, "Color Background for Open Trades", group=group_signal, tooltip="Green for Long, Red for Short")

group_exit = "Exit Settings"
use_ma_exit = input.bool(true, "Use MA Cross for Exit", group=group_exit)
ma_exit_length = input.int(20, "MA Length for Exit", minval=1, group=group_exit)
ma_exit_type = input.string("SMA", "MA Type for Exit", options=["SMA", "EMA", "SMMA (RMA)", "WMA", "VWMA"], group=group_exit)
use_adx_stop = input.bool(false, "Use ADX Change Stop-Loss", group=group_exit)
adx_change_percent = input.float(5.0, "ADX % Change for Stop-Loss", minval=0.0, step=0.1, group=group_exit, tooltip="Close trade if ADX changes by this % vs previous bar")
use_perf_stop = input.bool(false, "Use Performance Stop-Loss", group=group_exit, tooltip="Close trade if performance reaches this % loss")
perf_stop_percent = input.float(-10.0, "Performance Stop-Loss (%)", minval=-100.0, maxval=0.0, step=0.1, group=group_exit, tooltip="Negative % value for loss threshold")

// Trade Statistics Variables
var bool in_long = false
var bool in_short = false
var bool can_trade = strategy.equity > 0
var float initial_capital = strategy.initial_capital
var string open_trade_status = "No Open Trade"
var float long_trades = 0
var float short_trades = 0
var float long_wins = 0
var float short_wins = 0
var float entry_price = 0

// Calculations with Timeframe
[di_plus, di_minus, adx] = request.security(syminfo.tickerid, indicator_timeframe, ta.dmi(adx_di_len, adx_smooth_len))
cci = request.security(syminfo.tickerid, indicator_timeframe, ta.cci(cci_src, cci_length))
rsi = request.security(syminfo.tickerid, indicator_timeframe, ta.rsi(close, rsi_length))
atr = request.security(syminfo.tickerid, indicator_timeframe, ta.atr(atr_length))
volume_ma = request.security(syminfo.tickerid, indicator_timeframe, ta.sma(volume, volume_length))

ma_func(source, length, type, tf) =>
    switch type
        "SMA" => request.security(syminfo.tickerid, tf, ta.sma(source, length))
        "EMA" => request.security(syminfo.tickerid, tf, ta.ema(source, length))
        "SMMA (RMA)" => request.security(syminfo.tickerid, tf, ta.rma(source, length))
        "WMA" => request.security(syminfo.tickerid, tf, ta.wma(source, length))
        "VWMA" => request.security(syminfo.tickerid, tf, ta.vwma(source, length))

cci_ma = ma_func(cci, ma_length, ma_type, indicator_timeframe)
ma_exit = ma_func(close, ma_exit_length, ma_exit_type, indicator_timeframe)

// Plot MA if enabled (Global Scope)
plot(use_ma_exit ? ma_exit : na, "Exit MA", color=color.blue, linewidth=2)

// ADX Change Calculation
adx_change = ta.change(adx)
adx_prev = nz(adx[1], adx)
adx_percent_change = adx_prev != 0 ? math.abs(adx_change / adx_prev * 100) : 0
adx_stop_condition = use_adx_stop and adx_percent_change >= adx_change_percent

// Performance Stop-Loss Calculation
bool perf_stop_condition = false
if in_long and use_perf_stop
    perf_stop_condition := (close - entry_price) / entry_price * 100 <= perf_stop_percent
if in_short and use_perf_stop
    perf_stop_condition := (entry_price - close) / entry_price * 100 <= perf_stop_percent

// ATR Filter
atr_filter = not use_atr_filter or atr >= atr_threshold

// Volume Filter
volume_filter = not use_volume_filter or volume >= volume_ma * volume_threshold_multiplier

// Cross Detection
buy_cross_di = ta.crossover(di_plus, di_minus)
sell_cross_di = ta.crossover(di_minus, di_plus)
buy_cross_cci = ta.crossover(cci, cci_ma)
sell_cross_cci = ta.crossunder(cci, cci_ma)
long_exit_ma = ta.crossunder(close, ma_exit)
short_exit_ma = ta.crossover(close, ma_exit)

// Recent Cross Checks
buy_di_recent = ta.barssince(buy_cross_di) <= cross_window
sell_di_recent = ta.barssince(sell_cross_di) <= cross_window
buy_cci_recent = ta.barssince(buy_cross_cci) <= cross_window
sell_cci_recent = ta.barssince(sell_cross_cci) <= cross_window

// Signal Conditions
adx_filter = not use_adx_filter or adx > adx_threshold
rsi_buy_filter = not use_rsi_filter or rsi < rsi_lower_limit
rsi_sell_filter = not use_rsi_filter or rsi > rsi_upper_limit
buy_di_condition = buy_di_cross ? buy_di_recent : di_plus > di_minus
buy_cci_condition = buy_cci_cross ? buy_cci_recent : cci > cci_ma
sell_di_condition = sell_di_cross ? sell_di_recent : di_plus < di_minus
sell_cci_condition = sell_cci_cross ? sell_cci_recent : cci < cci_ma
buy_signal = buy_di_condition and buy_cci_condition and adx_filter and rsi_buy_filter and atr_filter and volume_filter
sell_signal = sell_di_condition and sell_cci_condition and adx_filter and rsi_sell_filter and atr_filter and volume_filter

// Alarms
alertcondition(buy_signal, title="Buy Signal Alert", message="ADXCCI Strategy: Buy Signal Triggered")
alertcondition(sell_signal, title="Sell Signal Alert", message="ADXCCI Strategy: Sell Signal Triggered")

// Strategy Entries and Labels
float chart_bottom = ta.lowest(low, 100)
if buy_signal and not in_long and allow_long and can_trade
    strategy.entry("Buy", strategy.long)
    label.new(bar_index, chart_bottom, "↑", color=color.green, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
    label.new(bar_index, chart_bottom, "BUY", color=color.green, style=label.style_label_up, textcolor=color.white, size=size.large, yloc=yloc.price)
    in_long := true
    in_short := false
    long_trades := long_trades + 1
    entry_price := close

if sell_signal and not in_short and allow_short and can_trade
    strategy.entry("Sell", strategy.short)
    label.new(bar_index, chart_bottom, "↓", color=color.red, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
    label.new(bar_index, chart_bottom, "SELL", color=color.red, style=label.style_label_up, textcolor=color.white, size=size.large, yloc=yloc.price)
    in_short := true
    in_long := false
    short_trades := short_trades + 1
    entry_price := close

// Reverse Exits (only if MA exit, ADX stop, and Perf stop are not used)
if not use_ma_exit and not adx_stop_condition and not perf_stop_condition
    if sell_signal and in_long
        strategy.close("Buy")
        label.new(bar_index, chart_bottom, "↓", color=color.green, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
        if close > entry_price
            long_wins := long_wins + 1
        in_long := false
        if countertrade and allow_short and can_trade
            strategy.entry("Sell", strategy.short)
            label.new(bar_index, chart_bottom, "↓", color=color.red, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
            label.new(bar_index, chart_bottom, "SELL", color=color.red, style=label.style_label_up, textcolor=color.white, size=size.large, yloc=yloc.price)
            in_short := true
            in_long := false
            short_trades := short_trades + 1
            entry_price := close
    if buy_signal and in_short
        strategy.close("Sell")
        label.new(bar_index, chart_bottom, "↑", color=color.red, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
        if close < entry_price
            short_wins := short_wins + 1
        in_short := false
        if countertrade and allow_long and can_trade
            strategy.entry("Buy", strategy.long)
            label.new(bar_index, chart_bottom, "↑", color=color.green, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
            label.new(bar_index, chart_bottom, "BUY", color=color.green, style=label.style_label_up, textcolor=color.white, size=size.large, yloc=yloc.price)
            in_long := true
            in_short := false
            long_trades := long_trades + 1
            entry_price := close

// MA Exit
if use_ma_exit
    if in_long and long_exit_ma
        strategy.close("Buy")
        label.new(bar_index, chart_bottom, "↓", color=color.green, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
        if close > entry_price
            long_wins := long_wins + 1
        in_long := false
        if countertrade and allow_short and can_trade
            strategy.entry("Sell", strategy.short)
            label.new(bar_index, chart_bottom, "↓", color=color.red, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
            label.new(bar_index, chart_bottom, "SELL", color=color.red, style=label.style_label_up, textcolor=color.white, size=size.large, yloc=yloc.price)
            in_short := true
            in_long := false
            short_trades := short_trades + 1
            entry_price := close
    if in_short and short_exit_ma
        strategy.close("Sell")
        label.new(bar_index, chart_bottom, "↑", color=color.red, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
        if close < entry_price
            short_wins := short_wins + 1
        in_short := false
        if countertrade and allow_long and can_trade
            strategy.entry("Buy", strategy.long)
            label.new(bar_index, chart_bottom, "↑", color=color.green, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
            label.new(bar_index, chart_bottom, "BUY", color=color.green, style=label.style_label_up, textcolor=color.white, size=size.large, yloc=yloc.price)
            in_long := true
            in_short := false
            long_trades := long_trades + 1
            entry_price := close

// ADX Stop-Loss
if adx_stop_condition
    if in_long
        strategy.close("Buy")
        label.new(bar_index, chart_bottom, "↓", color=color.green, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
        if close > entry_price
            long_wins := long_wins + 1
        in_long := false
        if countertrade and allow_short and can_trade
            strategy.entry("Sell", strategy.short)
            label.new(bar_index, chart_bottom, "↓", color=color.red, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
            label.new(bar_index, chart_bottom, "SELL", color=color.red, style=label.style_label_up, textcolor=color.white, size=size.large, yloc=yloc.price)
            in_short := true
            in_long := false
            short_trades := short_trades + 1
            entry_price := close
    if in_short
        strategy.close("Sell")
        label.new(bar_index, chart_bottom, "↑", color=color.red, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
        if close < entry_price
            short_wins := short_wins + 1
        in_short := false
        if countertrade and allow_long and can_trade
            strategy.entry("Buy", strategy.long)
            label.new(bar_index, chart_bottom, "↑", color=color.green, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
            label.new(bar_index, chart_bottom, "BUY", color=color.green, style=label.style_label_up, textcolor=color.white, size=size.large, yloc=yloc.price)
            in_long := true
            in_short := false
            long_trades := long_trades + 1
            entry_price := close

// Performance Stop-Loss
if perf_stop_condition
    if in_long
        strategy.close("Buy")
        label.new(bar_index, chart_bottom, "↓", color=color.green, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
        if close > entry_price
            long_wins := long_wins + 1
        in_long := false
        if countertrade and allow_short and can_trade
            strategy.entry("Sell", strategy.short)
            label.new(bar_index, chart_bottom, "↓", color=color.red, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
            label.new(bar_index, chart_bottom, "SELL", color=color.red, style=label.style_label_up, textcolor=color.white, size=size.large, yloc=yloc.price)
            in_short := true
            in_long := false
            short_trades := short_trades + 1
            entry_price := close
    if in_short
        strategy.close("Sell")
        label.new(bar_index, chart_bottom, "↑", color=color.red, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
        if close < entry_price
            short_wins := short_wins + 1
        in_short := false
        if countertrade and allow_long and can_trade
            strategy.entry("Buy", strategy.long)
            label.new(bar_index, chart_bottom, "↑", color=color.green, style=label.style_label_up, textcolor=color.white, size=size.normal, yloc=yloc.price)
            label.new(bar_index, chart_bottom, "BUY", color=color.green, style=label.style_label_up, textcolor=color.white, size=size.large, yloc=yloc.price)
            in_long := true
            in_short := false
            long_trades := long_trades + 1
            entry_price := close

// Warn if Equity is Negative
if not can_trade and (buy_signal or sell_signal)
    label.new(bar_index, close, "No Equity", color=color.yellow, style=label.style_label_center, textcolor=color.black, size=size.tiny)

// Background Coloring (Global Scope)
bgcolor(color_background ? (in_long ? color.new(color.green, 90) : in_short ? color.new(color.red, 90) : na) : na)